Adding cleaned up and commented MARC examples.
This commit is contained in:
parent
2aba3d62df
commit
4b6486f01c
|
@ -34,7 +34,7 @@ function makeParser() {
|
|||
parser.outs = [];
|
||||
|
||||
parser.on('object', function(name, obj) {
|
||||
if (Math.random() < 0.1) parseRecord(obj);
|
||||
if (Math.random() < 1) parseRecord(obj);
|
||||
});
|
||||
|
||||
parser.on('end', function() {
|
||||
|
@ -58,6 +58,8 @@ var callDict = {};
|
|||
var callYearTotals = [];
|
||||
|
||||
var allRecords = [];
|
||||
|
||||
|
||||
function parseRecord(obj) {
|
||||
|
||||
record = {};
|
||||
|
@ -216,7 +218,7 @@ function nextFile() {
|
|||
|
||||
console.log("LOADING FILE : " + url);
|
||||
counter ++;
|
||||
if (counter < 42) {
|
||||
if (counter < 10) {
|
||||
rstream // reads from myfile.txt.gz
|
||||
.pipe(gunzip) // uncompresses
|
||||
.pipe(parser.saxStream); //Parses into record objects
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,102 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="sigma/src/sigma.core.js"></script>
|
||||
<script src="sigma/src/conrad.js"></script>
|
||||
<script src="sigma/src/utils/sigma.utils.js"></script>
|
||||
<script src="sigma/src/utils/sigma.polyfills.js"></script>
|
||||
<script src="sigma/src/sigma.settings.js"></script>
|
||||
<script src="sigma/src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="sigma/src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="sigma/src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="sigma/src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="sigma/src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="sigma/src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="sigma/src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="sigma/src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="sigma/src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="sigma/src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="sigma/src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="sigma/src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="sigma/src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="sigma/src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="sigma/src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="sigma/src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="sigma/src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="sigma/src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="sigma/src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="sigma/src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="sigma/src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="sigma/src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="sigma/src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="sigma/src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="sigma/src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="sigma/src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="sigma/src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="sigma/src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="sigma/src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="sigma/src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="sigma/src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="sigma/src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="sigma/src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="sigma/src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="sigma/src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="sigma/src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="sigma/src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="sigma/src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="sigma/src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="sigma/src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="sigma/src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script src="sigma/plugins/sigma.layout.forceAtlas2/worker.js"></script>
|
||||
<script src="sigma/plugins/sigma.layout.forceAtlas2/supervisor.js"></script>
|
||||
<script src="sigma/plugins/sigma.parsers.json/sigma.parsers.json.js"></script>
|
||||
<script>
|
||||
|
||||
|
||||
var graph;
|
||||
|
||||
sigma.parsers.json('data/Occupation_network.json', {
|
||||
container: 'graph-container',
|
||||
renderer: {
|
||||
container: document.getElementById('graph-container'),
|
||||
type: 'canvas'
|
||||
},
|
||||
settings: {
|
||||
drawLabels: true,
|
||||
drawEdges: false,
|
||||
linLogMode: true,
|
||||
edgeWeightInfluence: 0,
|
||||
startingIterations: 10000,
|
||||
scalingRatio: 100,
|
||||
gravity:0,
|
||||
labelThreshold: 6,
|
||||
defaultNodeColor: "#AAAAAA"
|
||||
}
|
||||
}, function(s) {
|
||||
graph = s;
|
||||
s.startForceAtlas2({worker: true, barnesHutOptimize: false})
|
||||
});
|
||||
|
||||
function getCoords() {
|
||||
var nodes = graph.graph.nodes();
|
||||
var txt = JSON.stringify(nodes);
|
||||
var recipe = window.open('','ResultWindow','width=600,height=600');
|
||||
var html = '<html><head><title>Result Window</title></head><body><div>' + txt + '</div></body></html>';
|
||||
recipe.document.open();
|
||||
recipe.document.write(html);
|
||||
recipe.document.close();
|
||||
}
|
||||
|
||||
|
||||
</script>
|
|
@ -0,0 +1,6 @@
|
|||
node_modules/*
|
||||
build/*
|
||||
*.tgz
|
||||
*.log
|
||||
*.swp
|
||||
.DS_Store
|
|
@ -0,0 +1,13 @@
|
|||
build/*
|
||||
!build/sigma.require.js
|
||||
!build/sigma.min.js
|
||||
!build/plugins/*
|
||||
test/*
|
||||
node_modules/*
|
||||
examples/*
|
||||
Gruntfile.js
|
||||
CHANGELOG.md
|
||||
.travis.yml
|
||||
.gitignore
|
||||
*.tgz
|
||||
*.log
|
|
@ -0,0 +1,3 @@
|
|||
language: node_js
|
||||
before_script:
|
||||
- npm install -g grunt-cli
|
|
@ -0,0 +1,121 @@
|
|||
## sigma.js - changelog:
|
||||
|
||||
#### 1.2.1 - release (Oct 13, 2017)
|
||||
|
||||
- Fixing the [A*](https://github.com/jacomyal/sigma.js/tree/master/plugins/sigma.pathfinding.astar) plugin (thanks to [@RohitJV](https://github.com/RohitJV)).
|
||||
- Fixing SVG export (thanks to [@CarloLucibello](https://github.com/CarloLucibello)).
|
||||
|
||||
#### 1.2.0 - release (Nov 3, 2016)
|
||||
|
||||
- Added the [layout.noverlap](https://github.com/jacomyal/sigma.js/tree/master/plugins/sigma.layout.noverlap) plugin (thanks to [@apitts](https://github.com/apitts)).
|
||||
- Added the [renderers.edgeDot](https://github.com/jacomyal/sigma.js/tree/master/plugins/sigma.renderers.edgeDots) plugin (thanks to [@jotunacorn](https://github.com/jotunacorn)).
|
||||
- Fixed `sigma.require.js` so that Webpack & node.js can require the library.
|
||||
- Fixed camera zoom weird behavior on retina displays (thanks to [@robindemourat](https://github.com/robindemourat)).
|
||||
|
||||
#### 1.1.0 - release (Feb 17, 2016)
|
||||
|
||||
- Added the SVG renderer.
|
||||
- Added the `minArrowSize` setting (thanks to [@ssidorchick](https://github.com/ssidorchick)).
|
||||
- Added an edge quadtree and support for edge events (thanks to [@sheymann](https://github.com/sheymann)).
|
||||
- Fixed [#362](https://github.com/jacomyal/sigma.js/issues/362): Nodes and edges can now have a number id.
|
||||
- Added the [renderers.snapshot](https://github.com/jacomyal/sigma.js/tree/master/plugins/sigma.renderers.snapshot) plugin.
|
||||
- Fixed [#403](https://github.com/jacomyal/sigma.js/issues/403): renderer string container polymorphism.
|
||||
- Added an event dispatched when instance is killed.
|
||||
- Added low-level Barnes-Hut optimization to the [layout.forceAltas2](https://github.com/jacomyal/sigma.js/tree/master/plugins/sigma.layout.forceAtlas2) plugin (thanks to [@jacomyma](https://github.com/jacomyma)).
|
||||
- Added the `mouseWheelEnabled` setting.
|
||||
- Added an option to skip quadtree indexation when refreshing an instance.
|
||||
- Added `defaultEdgeType` and `defaultNodeType` settings.
|
||||
- Added a `isDragging` flag in click event.
|
||||
- Added some features to the [layout.forceAltas2](https://github.com/jacomyal/sigma.js/tree/master/plugins/sigma.layout.forceAtlas2) plugin.
|
||||
- Fixed resizing related issues.
|
||||
- Added the [SVG exporter](https://github.com/jacomyal/sigma.js/tree/master/plugins/sigma.exporters.svg) plugin.
|
||||
- Fixed some SVG-related bugs (thanks to [@qinfchen](https://github.com/qinfchen)).
|
||||
- Added the [A*](https://github.com/jacomyal/sigma.js/tree/master/plugins/sigma.pathfinding.astar) plugin (thanks to [@A----](https://github.com/A----)).
|
||||
- Changed the `singleHover` setting to default to `true`.
|
||||
- Added the [cypher](https://github.com/jacomyal/sigma.js/tree/master/plugins/sigma.parsers.cypher) plugin (thanks to [@sim51](https://github.com/sim51)).
|
||||
- Added the [parallel edges](https://github.com/jacomyal/sigma.js/tree/master/plugins/sigma.renderers.parallelEdges) plugin (thanks to [@3ch01c](https://github.com/3ch01c)).
|
||||
- Added HDPI screens support (thanks to [@mdamien](https://github.com/mdamien)).
|
||||
- Fixed a ForceAtlas2 bug related to the `ajustSizes` setting (thanks to [@rangeonnicolas](https://github.com/rangeonnicolas)).
|
||||
- Improved `sigma.webgl.nodes.fast` implementaton.
|
||||
- Added some alternatives to `sigma.webgl.edges.def`.
|
||||
- Various optimizations.
|
||||
|
||||
#### 1.0.3 - release (August 22, 2014)
|
||||
|
||||
- Fixed [#186](https://github.com/jacomyal/sigma.js/issues/186): NPM sigma package
|
||||
- New helper `sigma.utils.zoomTo` (thanks to [@josemazo](https://github.com/josemazo))
|
||||
- Fixed [#241](https://github.com/jacomyal/sigma.js/issues/241): Improved canvas renderer
|
||||
- Fixed [#244](https://github.com/jacomyal/sigma.js/issues/244): (min|max)(Node|Edge)Size as strings or numbers
|
||||
- Cross available in the customShapes plugin (thanks to [@csweaver](https://github.com/csweaver))
|
||||
- [Relative size](https://github.com/jacomyal/sigma.js/tree/master/plugins/sigma.plugins.relativeSize) plugin (thanks to [@tsdaemon](https://github.com/tsdaemon))
|
||||
- Fixed y positions from sigma.parsers.gexf (thanks to [@totetmatt](https://github.com/totetmatt))
|
||||
- Fixed lag problem for the dragNodes plugin on Firefox (thanks to [@apitts](https://github.com/apitts))
|
||||
- Added the `singleHover` settings (thanks to [@patrickmarabeas](https://github.com/patrickmarabeas))
|
||||
- Improved dragNodes behaviours with several hovered nodes (thanks to [@patrickmarabeas](https://github.com/patrickmarabeas))
|
||||
- Added self-loops rendering for curved edges (thanks to [@ssidorchick](https://github.com/ssidorchick))
|
||||
- Updated gexfParser.js version
|
||||
- [HITS statistics computation](https://github.com/jacomyal/sigma.js/tree/master/plugins/sigma.statistics.HITS) plugin (thanks to [@mef](https://github.com/mef))
|
||||
- Fixed [#299](https://github.com/jacomyal/sigma.js/issues/299): Fixed `npm build`
|
||||
- Fixed [#332](https://github.com/jacomyal/sigma.js/issues/332): Fixed grunt tasks for building plugins
|
||||
- Fixed [#347](https://github.com/jacomyal/sigma.js/issues/347): Added polymorphism for the autoRescale setting
|
||||
- Fixed build for Force-Atlas 2 plugin (thanks to [@luca](https://github.com/luca))
|
||||
- Fixed some typos (thanks to [@Tal-Daniel](https://github.com/Tal-Daniel))
|
||||
- [Custom edge shapes](https://github.com/jacomyal/sigma.js/tree/master/plugins/sigma.renderers.customEdgeShapes) plugin (thanks to [@sheymann](https://github.com/sheymann))
|
||||
- [Filter API](https://github.com/jacomyal/sigma.js/tree/master/plugins/sigma.plugins.filter) plugin (thanks to [@sheymann](https://github.com/sheymann))
|
||||
- Right-click support (thanks to [@sheymann](https://github.com/sheymann))
|
||||
- Event data now always dispatched by sigma.core (thanks to [@sheymann](https://github.com/sheymann))
|
||||
- Added the `attachBefore` method to `sigma.classes.graph` (thanks to [@sheymann](https://github.com/sheymann))
|
||||
- Fixed buggy behaviour with the dragNodes plugin when container is offset (thanks to [@Pie21](https://github.com/Pie21))
|
||||
- Updated NPM dev dependencies
|
||||
- Fixed a leak in `sigma.classes.graph` (details at [#340](https://github.com/jacomyal/sigma.js/issues/340))
|
||||
- **WebGL based Force-Atlas 2**
|
||||
|
||||
#### 1.0.2 - release (April 2, 2014)
|
||||
|
||||
- Added Canvas curved edge renderer
|
||||
- Fully refactored examples
|
||||
- Fixed [#211](https://github.com/jacomyal/sigma.js/issues/211): Added default camera getter
|
||||
- Fixes on ForceAtlas2 API (thanks to [@adkatrit](https://github.com/adkatrit))
|
||||
- Added Canvas curved arrows edge renderer (thanks to [@ssidorchick](https://github.com/ssidorchick))
|
||||
- Fixed [#220](https://github.com/jacomyal/sigma.js/issues/220): WebGL edges batch rendering fixed
|
||||
- Fixed [#175](https://github.com/jacomyal/sigma.js/issues/175): Disable setAutoSettings in ForceAtlas2
|
||||
- Fixed some minor typos (thanks to [@anirvan](https://github.com/anirvan))
|
||||
- Added the `sigma.plugins.dragNodes` plugin for the Canvas renderer (thanks to [@josemazo](https://github.com/josemazo))
|
||||
- Fixed `gjslint.py does not exist` error (thanks to [@jeroencoumans](https://github.com/jeroencoumans))
|
||||
- Made it easier to build for newbies by not requiring global `grunt-cli` (thanks to [@eins78](https://github.com/eins78))
|
||||
- Some minor changes on docs and GEXF parser (thanks to [@Yomguithereal](https://github.com/Yomguithereal))
|
||||
- Added current version number as `sigma.version`
|
||||
- Fixed [#236](https://github.com/jacomyal/sigma.js/issues/236): Implemented `kill` renderers method
|
||||
|
||||
#### 1.0.1 - release (February 26, 2014)
|
||||
|
||||
- Custom node shapes and images plug-in (thanks to [@rpeleg1970](https://github.com/rpeleg1970))
|
||||
- Fixed [#189](https://github.com/jacomyal/sigma.js/issues/189): Added doubleClick events
|
||||
- Fixed [#183](https://github.com/jacomyal/sigma.js/issues/183): Avoid using `for in` to iterate over arrays (thanks to [@cdevienne](https://github.com/cdevienne))
|
||||
- Added `http-server` dependency (thanks to [@oncletom](https://github.com/oncletom))
|
||||
- Minor fix in LICENSE.txt (thanks to [@gdi2290](https://github.com/gdi2290))
|
||||
- Added `"hidden"` nodes and edges support
|
||||
- Fixed typo in `sigma.instances` method (thanks to [@juanpastas](https://github.com/juanpastas))
|
||||
- Fixed ForceAtlas2 stopForceAtlas2 method
|
||||
- Improved captors
|
||||
- Plus some minor and various fixes...
|
||||
|
||||
#### 1.0.0 - release (January 30, 2014)
|
||||
|
||||
- Finalization:
|
||||
* Closed issues related to the initial version that were not relevant in this new version
|
||||
* Fixed some bugs in the new version related to both versions
|
||||
* Added more plugins and code samples, to solve some actual use-cases
|
||||
* Fixed a lot of bugs for the release
|
||||
|
||||
#### 1.0.0 - draft (November 27, 2013)
|
||||
|
||||
- Full new version of sigma from scratch, including old features:
|
||||
* ForceAtlas2 plugin
|
||||
* GEXF parser
|
||||
* Canvas renderer
|
||||
- ...and some new features:
|
||||
* WebGL renderer
|
||||
* Touch support
|
||||
- Also added some unit tests (main classes, core API, ...).
|
||||
- Architecture fully rewritten
|
|
@ -0,0 +1,47 @@
|
|||
## sigma.js - how to contribute:
|
||||
|
||||
As an open-source project that is maintained by people who cannot work on it on a daily basis, contributions are very welcome! But there are some rules to follow, to prevent maintainers to spend too much time on irrelevant or invalid contributions.
|
||||
|
||||
#### Opening a ticket
|
||||
|
||||
First, here are some basic rules:
|
||||
|
||||
- Make sure your bug or question has not been addressed in another ticket yet.
|
||||
- If your ticket is related to a bug you've met, please add a simple use-case to help the maintainers reproduce the bug.
|
||||
|
||||
##### A word about labels
|
||||
|
||||
We use three labels to estimate the time a ticket will take us to solve:
|
||||
|
||||
- **cake**: This issue will probably take only some minutes to solve.
|
||||
- **steak**: This issue will probably take around one or two hours to solve.
|
||||
- **snake**: This issue will probably take more than two hours to solve.
|
||||
|
||||
#### Submitting a pull-request
|
||||
|
||||
##### What can be submitted
|
||||
|
||||
First, sigma has been designed as a tool. Since two network visualization applications will have different features and interactions if they are developed by different people or for different use cases, the potentially needed features are countless.
|
||||
|
||||
So, sigma aims to make it possible for developers to implement the features they need for their applications through its API, but should not contain itself these features.
|
||||
|
||||
So, basically:
|
||||
|
||||
- If your feature can be implemented with sigma, then you can submit it as a plugin, to help other people use it easily.
|
||||
- If for some reason you needed to modify sigma to implement your feature, you can submit these modifications to improve sigma.
|
||||
|
||||
But:
|
||||
|
||||
- If you submit new features in sigma that can be developed as plugins, they will probably not be accepted.
|
||||
|
||||
##### Some basic rules
|
||||
|
||||
If you submit modifications to sigma, please ensure that:
|
||||
|
||||
1. the unit tests still pass
|
||||
2. your code respect JSHint and ClosureLint rules
|
||||
3. you cleaned your code from commented lines, logs, alerts or other debugging related code.
|
||||
|
||||
You can check these rules by running `grunt` in sigma's directory from your command line.
|
||||
|
||||
Also, if you submit a plugin, please add an example that shows how the plugins works and what it does.
|
|
@ -0,0 +1,206 @@
|
|||
var fs = require('fs');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
var coreJsFiles = [
|
||||
// Core:
|
||||
'src/sigma.core.js',
|
||||
|
||||
// Utils:
|
||||
'src/conrad.js',
|
||||
'src/utils/sigma.utils.js',
|
||||
'src/utils/sigma.polyfills.js',
|
||||
|
||||
// Main classes:
|
||||
'src/sigma.settings.js',
|
||||
'src/classes/sigma.classes.dispatcher.js',
|
||||
'src/classes/sigma.classes.configurable.js',
|
||||
'src/classes/sigma.classes.graph.js',
|
||||
'src/classes/sigma.classes.camera.js',
|
||||
'src/classes/sigma.classes.quad.js',
|
||||
'src/classes/sigma.classes.edgequad.js',
|
||||
|
||||
// Captors:
|
||||
'src/captors/sigma.captors.mouse.js',
|
||||
'src/captors/sigma.captors.touch.js',
|
||||
|
||||
// Renderers:
|
||||
'src/renderers/sigma.renderers.canvas.js',
|
||||
'src/renderers/sigma.renderers.webgl.js',
|
||||
'src/renderers/sigma.renderers.svg.js',
|
||||
'src/renderers/sigma.renderers.def.js',
|
||||
|
||||
// Sub functions per engine:
|
||||
'src/renderers/webgl/sigma.webgl.nodes.def.js',
|
||||
'src/renderers/webgl/sigma.webgl.nodes.fast.js',
|
||||
'src/renderers/webgl/sigma.webgl.edges.def.js',
|
||||
'src/renderers/webgl/sigma.webgl.edges.fast.js',
|
||||
'src/renderers/webgl/sigma.webgl.edges.arrow.js',
|
||||
'src/renderers/canvas/sigma.canvas.labels.def.js',
|
||||
'src/renderers/canvas/sigma.canvas.hovers.def.js',
|
||||
'src/renderers/canvas/sigma.canvas.nodes.def.js',
|
||||
'src/renderers/canvas/sigma.canvas.edges.def.js',
|
||||
'src/renderers/canvas/sigma.canvas.edges.dotCurve.js',
|
||||
'src/renderers/canvas/sigma.canvas.edges.arrow.js',
|
||||
'src/renderers/canvas/sigma.canvas.edges.dotCurvedArrow.js',
|
||||
'src/renderers/canvas/sigma.canvas.edgehovers.def.js',
|
||||
'src/renderers/canvas/sigma.canvas.edgehovers.curve.js',
|
||||
'src/renderers/canvas/sigma.canvas.edgehovers.arrow.js',
|
||||
'src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js',
|
||||
'src/renderers/canvas/sigma.canvas.extremities.def.js',
|
||||
'src/renderers/svg/sigma.svg.utils.js',
|
||||
'src/renderers/svg/sigma.svg.nodes.def.js',
|
||||
'src/renderers/svg/sigma.svg.edges.def.js',
|
||||
'src/renderers/svg/sigma.svg.edges.curve.js',
|
||||
'src/renderers/svg/sigma.svg.labels.def.js',
|
||||
'src/renderers/svg/sigma.svg.hovers.def.js',
|
||||
|
||||
// Middlewares:
|
||||
'src/middlewares/sigma.middlewares.rescale.js',
|
||||
'src/middlewares/sigma.middlewares.copy.js',
|
||||
|
||||
// Miscellaneous:
|
||||
'src/misc/sigma.misc.animation.js',
|
||||
'src/misc/sigma.misc.bindEvents.js',
|
||||
'src/misc/sigma.misc.bindDOMEvents.js',
|
||||
'src/misc/sigma.misc.drawHovers.js'
|
||||
];
|
||||
|
||||
var npmJsFiles = coreJsFiles.slice(0);
|
||||
npmJsFiles.splice(2, 0, 'src/sigma.export.js');
|
||||
|
||||
var plugins = [
|
||||
'exporters.svg',
|
||||
'layout.forceAtlas2',
|
||||
'layout.noverlap',
|
||||
'neo4j.cypher',
|
||||
'parsers.gexf',
|
||||
'parsers.json',
|
||||
'pathfinding.astar',
|
||||
'plugins.animate',
|
||||
'plugins.dragNodes',
|
||||
'plugins.filter',
|
||||
'plugins.neighborhoods',
|
||||
'plugins.relativeSize',
|
||||
'renderers.customEdgeShapes',
|
||||
'renderers.customShapes',
|
||||
'renderers.edgeDots',
|
||||
'renderers.edgeLabels',
|
||||
'renderers.parallelEdges',
|
||||
'renderers.snapshot',
|
||||
'statistics.HITS'
|
||||
];
|
||||
|
||||
var pluginFiles = [],
|
||||
subGrunts = {};
|
||||
|
||||
plugins.forEach(function(p) {
|
||||
var dir = 'plugins/sigma.' + p + '/';
|
||||
|
||||
if (fs.existsSync(dir + 'Gruntfile.js'))
|
||||
subGrunts[p] = {
|
||||
gruntfile: dir + 'Gruntfile.js'
|
||||
};
|
||||
else
|
||||
pluginFiles.push(dir + '**/*.js');
|
||||
});
|
||||
|
||||
// Project configuration:
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
grunt: subGrunts,
|
||||
closureLint: {
|
||||
app: {
|
||||
closureLinterPath: '/usr/local/bin',
|
||||
command: 'gjslint',
|
||||
src: coreJsFiles,
|
||||
options: {
|
||||
stdout: true,
|
||||
strict: true,
|
||||
opt: '--disable 6,13'
|
||||
}
|
||||
}
|
||||
},
|
||||
jshint: {
|
||||
all: coreJsFiles,
|
||||
options: {
|
||||
'-W055': true,
|
||||
'-W040': true,
|
||||
'-W064': true
|
||||
}
|
||||
},
|
||||
qunit: {
|
||||
all: {
|
||||
options: {
|
||||
urls: [
|
||||
'./test/unit.html'
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
uglify: {
|
||||
prod: {
|
||||
files: {
|
||||
'build/sigma.min.js': coreJsFiles
|
||||
},
|
||||
options: {
|
||||
banner: '/* sigma.js - <%= pkg.description %> - Version: <%= pkg.version %> - Author: Alexis Jacomy, Sciences-Po Médialab - License: MIT */\n'
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
files: pluginFiles.reduce(function(res, path) {
|
||||
var dest = 'build/' + path.replace(/\/\*\*\/\*\.js$/, '.min.js');
|
||||
res[dest] = path;
|
||||
return res;
|
||||
}, {})
|
||||
}
|
||||
},
|
||||
concat: {
|
||||
options: {
|
||||
separator: '\n'
|
||||
},
|
||||
dist: {
|
||||
src: coreJsFiles,
|
||||
dest: 'build/sigma.js'
|
||||
},
|
||||
require: {
|
||||
src: npmJsFiles,
|
||||
dest: 'build/sigma.require.js'
|
||||
}
|
||||
},
|
||||
sed: {
|
||||
version: {
|
||||
recursive: true,
|
||||
path: 'examples/',
|
||||
pattern: /<!-- START SIGMA IMPORTS -->[\s\S]*<!-- END SIGMA IMPORTS -->/g,
|
||||
replacement: ['<!-- START SIGMA IMPORTS -->'].concat(coreJsFiles.map(function(path) {
|
||||
return '<script src="../' + path + '"></script>';
|
||||
}).concat('<!-- END SIGMA IMPORTS -->')).join('\n')
|
||||
}
|
||||
},
|
||||
zip: {
|
||||
release: {
|
||||
dest: 'build/release-v<%= pkg.version %>.zip',
|
||||
src: [
|
||||
'README.md',
|
||||
'build/sigma.min.js',
|
||||
'build/plugins/*.min.js'
|
||||
],
|
||||
router: function(filepath) {
|
||||
return filepath.replace(/build\//, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
require('load-grunt-tasks')(grunt);
|
||||
|
||||
// By default, will check lint, hint, test and minify:
|
||||
grunt.registerTask('default', ['closureLint', 'jshint', 'qunit', 'sed', 'grunt', 'uglify']);
|
||||
grunt.registerTask('release', ['closureLint', 'jshint', 'qunit', 'sed', 'grunt', 'uglify', 'zip']);
|
||||
grunt.registerTask('npmPrePublish', ['uglify:plugins', 'grunt', 'concat:require']);
|
||||
grunt.registerTask('build', ['uglify', 'grunt', 'concat:require']);
|
||||
grunt.registerTask('test', ['qunit']);
|
||||
|
||||
// For travis-ci.org, only launch tests:
|
||||
grunt.registerTask('travis', ['qunit']);
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
Copyright (C) 2013-2014, Alexis Jacomy, http://sigmajs.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
|
@ -0,0 +1,35 @@
|
|||
[![Build Status](https://travis-ci.org/jacomyal/sigma.js.svg)](https://travis-ci.org/jacomyal/sigma.js)
|
||||
|
||||
sigma.js - v1.2.1
|
||||
=================
|
||||
|
||||
Sigma is a JavaScript library dedicated to graph drawing, mainly developed by [@jacomyal](https://github.com/jacomyal) and [@Yomguithereal](https://github.com/Yomguithereal).
|
||||
|
||||
### Resources
|
||||
|
||||
[The website](http://sigmajs.org) provides a global overview of the project, and the documentation is available in the [Github Wiki](https://github.com/jacomyal/sigma.js/wiki).
|
||||
|
||||
Also, the `plugins` and `examples` directories contain various use-cases that might help you understand how to use sigma.
|
||||
|
||||
### How to use it
|
||||
|
||||
To use it, clone the repository:
|
||||
|
||||
```
|
||||
git clone git@github.com:jacomyal/sigma.js.git
|
||||
```
|
||||
|
||||
To build the code:
|
||||
|
||||
- Install [Node.js](http://nodejs.org/).
|
||||
- Install [gjslint](https://developers.google.com/closure/utilities/docs/linter_howto?hl=en).
|
||||
- Use `npm install` to install sigma development dependencies.
|
||||
- Use `npm run build` to minify the code with [Uglify](https://github.com/mishoo/UglifyJS). The minified file `sigma.min.js` will then be accessible in the `build/` folder.
|
||||
|
||||
Also, you can customize the build by adding or removing files from the `coreJsFiles` array in `Gruntfile.js` before applying the grunt task.
|
||||
|
||||
### Contributing
|
||||
|
||||
You can contribute by submitting [issues tickets](http://github.com/jacomyal/sigma.js/issues) and proposing [pull requests](http://github.com/jacomyal/sigma.js/pulls). Make sure that tests and linting pass before submitting any pull request by running the command `grunt`.
|
||||
|
||||
The whole source code is validated by the [Google Closure Linter](https://developers.google.com/closure/utilities/) and [JSHint](http://www.jshint.com/), and the comments are written in [JSDoc](http://en.wikipedia.org/wiki/JSDoc) (tags description is available [here](https://developers.google.com/closure/compiler/docs/js-for-compiler)).
|
|
@ -0,0 +1,464 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
background: #fff;
|
||||
height: 600px;
|
||||
max-width: 800px;
|
||||
margin: auto;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#disc {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#ground {
|
||||
position: absolute;
|
||||
background: #ccc;
|
||||
top: 100%;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container">
|
||||
<div id="disc"></div>
|
||||
<div id="ground"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var s,
|
||||
c,
|
||||
dom,
|
||||
disc,
|
||||
ground,
|
||||
nId = 0,
|
||||
eId = 0,
|
||||
radius = 50,
|
||||
|
||||
mouseX,
|
||||
mouseY,
|
||||
spaceMode = false,
|
||||
wheelRatio = 1.1,
|
||||
|
||||
nodeRadius = 10,
|
||||
inertia = 0.8,
|
||||
springForce = 0.01,
|
||||
springLength = 50,
|
||||
maxDisplacement = 15,
|
||||
gravity = 1.5;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* CUSTOM PHYSICS LAYOUT:
|
||||
* **********************
|
||||
*/
|
||||
sigma.classes.graph.addMethod('computePhysics', function() {
|
||||
var i,
|
||||
j,
|
||||
l = this.nodesArray.length,
|
||||
|
||||
s,
|
||||
t,
|
||||
dX,
|
||||
dY,
|
||||
d,
|
||||
v;
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
s = this.nodesArray[i];
|
||||
s.dX *= inertia;
|
||||
s.dY *= inertia;
|
||||
|
||||
s.dY += gravity;
|
||||
|
||||
for (j = i + 1; j < l; j++) {
|
||||
t = this.nodesArray[j];
|
||||
|
||||
dX = s.x - t.x;
|
||||
dY = s.y - t.y;
|
||||
d = Math.sqrt(dX * dX + dY * dY);
|
||||
v = ((d < 2 * nodeRadius) ? (2 * nodeRadius - d) / d / 2 : 0) -
|
||||
((this.allNeighborsIndex[s.id] || {})[t.id] ? springForce * (d - springLength) : 0);
|
||||
|
||||
t.dX -= v * dX;
|
||||
t.dY -= v * dY;
|
||||
s.dX += v * dX;
|
||||
s.dY += v * dY;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
s = this.nodesArray[i];
|
||||
s.dX = Math.max(Math.min(s.dX, maxDisplacement), -maxDisplacement);
|
||||
s.dY = Math.max(Math.min(s.dY, maxDisplacement), -maxDisplacement);
|
||||
s.x += s.dX;
|
||||
s.y += s.dY;
|
||||
|
||||
// Collision with the ground:
|
||||
s.y = Math.min(-nodeRadius, s.y);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* CUSTOM RENDERERS:
|
||||
* *****************
|
||||
*/
|
||||
sigma.canvas.edges.goo = function(e, s, t, ctx, settings) {
|
||||
var color = e.color,
|
||||
p = settings('prefix') || '',
|
||||
edgeColor = settings('edgeColor'),
|
||||
defaultNodeColor = settings('defaultNodeColor'),
|
||||
defaultEdgeColor = settings('defaultEdgeColor'),
|
||||
v,
|
||||
d,
|
||||
p1 = 5 / 6,
|
||||
p2 = 1 / 6;
|
||||
|
||||
if (!color)
|
||||
switch (edgeColor) {
|
||||
case 'source':
|
||||
color = s.color || defaultNodeColor;
|
||||
break;
|
||||
case 'target':
|
||||
color = t.color || defaultNodeColor;
|
||||
break;
|
||||
default:
|
||||
color = defaultEdgeColor;
|
||||
break;
|
||||
}
|
||||
|
||||
d = Math.sqrt(Math.pow(t[p + 'x'] - s[p + 'x'], 2) + Math.pow(t[p + 'y'] - s[p + 'y'], 2));
|
||||
v = {
|
||||
x: (t[p + 'x'] - s[p + 'x']) / d,
|
||||
y: (t[p + 'y'] - s[p + 'y']) / d
|
||||
};
|
||||
|
||||
ctx.fillStyle = color;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(
|
||||
s[p + 'x'] + v.y * s[p + 'size'],
|
||||
s[p + 'y'] - v.x * s[p + 'size']
|
||||
);
|
||||
ctx.bezierCurveTo(
|
||||
s[p + 'x'] * p1 + t[p + 'x'] * p2 + v.y * e[p + 'size'],
|
||||
s[p + 'y'] * p1 + t[p + 'y'] * p2 - v.x * e[p + 'size'],
|
||||
t[p + 'x'] * p1 + s[p + 'x'] * p2 + v.y * e[p + 'size'],
|
||||
t[p + 'y'] * p1 + s[p + 'y'] * p2 - v.x * e[p + 'size'],
|
||||
t[p + 'x'] + v.y * t[p + 'size'],
|
||||
t[p + 'y'] - v.x * t[p + 'size']
|
||||
);
|
||||
ctx.lineTo(
|
||||
t[p + 'x'] - v.y * t[p + 'size'],
|
||||
t[p + 'y'] + v.x * t[p + 'size']
|
||||
);
|
||||
ctx.bezierCurveTo(
|
||||
t[p + 'x'] * p1 + s[p + 'x'] * p2 - v.y * e[p + 'size'],
|
||||
t[p + 'y'] * p1 + s[p + 'y'] * p2 + v.x * e[p + 'size'],
|
||||
s[p + 'x'] * p1 + t[p + 'x'] * p2 - v.y * e[p + 'size'],
|
||||
s[p + 'y'] * p1 + t[p + 'y'] * p2 + v.x * e[p + 'size'],
|
||||
s[p + 'x'] - v.y * s[p + 'size'],
|
||||
s[p + 'y'] + v.x * s[p + 'size']
|
||||
);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
};
|
||||
|
||||
sigma.canvas.nodes.goo = function(node, ctx, settings) {
|
||||
var prefix = settings('prefix') || '';
|
||||
|
||||
ctx.fillStyle = node.color || settings('defaultNodeColor');
|
||||
ctx.beginPath();
|
||||
ctx.arc(
|
||||
node[prefix + 'x'],
|
||||
node[prefix + 'y'],
|
||||
node[prefix + 'size'],
|
||||
0,
|
||||
Math.PI * 2,
|
||||
true
|
||||
);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.beginPath();
|
||||
ctx.arc(
|
||||
node[prefix + 'x'],
|
||||
node[prefix + 'y'],
|
||||
node[prefix + 'size'] * 0.5,
|
||||
0,
|
||||
Math.PI * 2,
|
||||
true
|
||||
);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* INITIALIZATION SCRIPT:
|
||||
* **********************
|
||||
*/
|
||||
s = new sigma({
|
||||
renderer: {
|
||||
container: document.getElementById('graph-container'),
|
||||
type: 'canvas'
|
||||
},
|
||||
settings: {
|
||||
autoRescale: false,
|
||||
mouseEnabled: false,
|
||||
touchEnabled: false,
|
||||
nodesPowRatio: 1,
|
||||
edgesPowRatio: 1,
|
||||
defaultEdgeColor: '#333',
|
||||
defaultNodeColor: '#333',
|
||||
edgeColor: 'default'
|
||||
}
|
||||
});
|
||||
dom = document.querySelector('#graph-container canvas:last-child');
|
||||
disc = document.getElementById('disc');
|
||||
ground = document.getElementById('ground');
|
||||
c = s.camera;
|
||||
|
||||
// Initialize graph:
|
||||
s.graph.read({
|
||||
nodes: [
|
||||
{
|
||||
id: (++nId) + '',
|
||||
size: nodeRadius,
|
||||
x: 0,
|
||||
y: -80,
|
||||
dX: 0,
|
||||
dY: 0,
|
||||
type: 'goo'
|
||||
},
|
||||
{
|
||||
id: (++nId) + '',
|
||||
size: nodeRadius,
|
||||
x: 10,
|
||||
y: -100,
|
||||
dX: 0,
|
||||
dY: 0,
|
||||
type: 'goo'
|
||||
},
|
||||
{
|
||||
id: (++nId) + '',
|
||||
size: nodeRadius,
|
||||
x: 20,
|
||||
y: -80,
|
||||
dX: 0,
|
||||
dY: 0,
|
||||
type: 'goo'
|
||||
}
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
id: (++eId) + '',
|
||||
source: '1',
|
||||
target: '2',
|
||||
type: 'goo'
|
||||
},
|
||||
{
|
||||
id: (++eId) + '',
|
||||
source: '1',
|
||||
target: '3',
|
||||
type: 'goo'
|
||||
},
|
||||
{
|
||||
id: (++eId) + '',
|
||||
source: '2',
|
||||
target: '3',
|
||||
type: 'goo'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
function frame() {
|
||||
s.graph.computePhysics();
|
||||
s.refresh();
|
||||
|
||||
if (s.graph.nodes().length) {
|
||||
var w = dom.offsetWidth,
|
||||
h = dom.offsetHeight;
|
||||
|
||||
// The "rescale" middleware modifies the position of the nodes, but we
|
||||
// need here the camera to deal with this. Here is the code:
|
||||
var xMin = Infinity,
|
||||
xMax = -Infinity,
|
||||
yMin = Infinity,
|
||||
yMax = -Infinity,
|
||||
margin = 50,
|
||||
scale;
|
||||
|
||||
s.graph.nodes().forEach(function(n) {
|
||||
xMin = Math.min(n.x, xMin);
|
||||
xMax = Math.max(n.x, xMax);
|
||||
yMin = Math.min(n.y, yMin);
|
||||
yMax = Math.max(n.y, yMax);
|
||||
});
|
||||
|
||||
xMax += margin;
|
||||
xMin -= margin;
|
||||
yMax += margin;
|
||||
yMin -= margin;
|
||||
|
||||
scale = Math.min(
|
||||
w / Math.max(xMax - xMin, 1),
|
||||
h / Math.max(yMax - yMin, 1)
|
||||
);
|
||||
|
||||
c.goTo({
|
||||
x: (xMin + xMax) / 2,
|
||||
y: (yMin + yMax) / 2,
|
||||
ratio: 1 / scale
|
||||
});
|
||||
|
||||
ground.style.top =
|
||||
Math.max(h / 2 - Math.min((yMin + yMax) / 2 * scale, h), 0) + 'px';
|
||||
disc.style.borderRadius = radius * scale;
|
||||
disc.style.width = 2 * radius * scale;
|
||||
disc.style.height = 2 * radius * scale;
|
||||
disc.style.top = mouseY - radius * scale;
|
||||
disc.style.left = mouseX - radius * scale;
|
||||
disc.style.backgroundColor = spaceMode ? '#f99' : '#9cf';
|
||||
|
||||
}
|
||||
|
||||
requestAnimationFrame(frame);
|
||||
}
|
||||
|
||||
frame();
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* EVENTS BINDING:
|
||||
* ***************
|
||||
*/
|
||||
dom.addEventListener('click', function(e) {
|
||||
// Find neighbors:
|
||||
var x,
|
||||
y,
|
||||
p,
|
||||
id,
|
||||
neighbors;
|
||||
|
||||
x = sigma.utils.getX(e) - dom.offsetWidth / 2;
|
||||
y = sigma.utils.getY(e) - dom.offsetHeight / 2;
|
||||
|
||||
p = c.cameraPosition(x, y);
|
||||
x = p.x;
|
||||
y = p.y;
|
||||
|
||||
neighbors = s.graph.nodes().filter(function(n) {
|
||||
return (Math.sqrt(
|
||||
Math.pow(n.x - x, 2) +
|
||||
Math.pow(n.y - y, 2)
|
||||
) - n.size) < radius;
|
||||
});
|
||||
|
||||
if (!spaceMode)
|
||||
s.graph.addNode({
|
||||
id: (id = (++nId) + ''),
|
||||
size: nodeRadius,
|
||||
x: x + Math.random() / 10,
|
||||
y: y + Math.random() / 10,
|
||||
dX: 0,
|
||||
dY: 0,
|
||||
type: 'goo'
|
||||
});
|
||||
|
||||
neighbors.forEach(function(n) {
|
||||
if (!spaceMode)
|
||||
s.graph.addEdge({
|
||||
id: (++eId) + '',
|
||||
source: id,
|
||||
target: n.id,
|
||||
type: 'goo'
|
||||
});
|
||||
else
|
||||
s.graph.dropNode(n.id);
|
||||
});
|
||||
}, false);
|
||||
dom.addEventListener('mousemove', function(e) {
|
||||
mouseX = sigma.utils.getX(e);
|
||||
mouseY = sigma.utils.getY(e);
|
||||
}, false);
|
||||
dom.addEventListener('DOMMouseScroll', function(e) {
|
||||
radius *= sigma.utils.getDelta(e) < 0 ? 1 / wheelRatio : wheelRatio;
|
||||
}, false);
|
||||
dom.addEventListener('mousewheel', function(e) {
|
||||
radius *= sigma.utils.getDelta(e) < 0 ? 1 / wheelRatio : wheelRatio;
|
||||
}, false);
|
||||
document.addEventListener('keydown', function(e) {
|
||||
spaceMode = (e.which == 32) ? true : spaceMode;
|
||||
});
|
||||
document.addEventListener('keyup', function(e) {
|
||||
spaceMode = e.which == 32 ? false : spaceMode;
|
||||
});
|
||||
})();
|
||||
</script>
|
|
@ -0,0 +1,139 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.plugins.animate/sigma.plugins.animate.js"></script>
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This example shows how to use the sigma.plugins.animate plugin. It
|
||||
* creates a random graph with two different views:
|
||||
*
|
||||
* The circular view displays the nodes on a circle, with each node
|
||||
* having a random color and a random size.
|
||||
*
|
||||
* The grid view displays every nodes with the same size, and on a grid.
|
||||
*
|
||||
* Every two seconds, the graph will be animated from a view to the other
|
||||
* one, in a one second animation.
|
||||
*/
|
||||
var i,
|
||||
s,
|
||||
o,
|
||||
L = 10,
|
||||
N = 100,
|
||||
E = 500,
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
},
|
||||
step = 0;
|
||||
|
||||
// Generate a random graph:
|
||||
for (i = 0; i < N; i++) {
|
||||
o = {
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
circular_x: L * Math.cos(Math.PI * 2 * i / N - Math.PI / 2),
|
||||
circular_y: L * Math.sin(Math.PI * 2 * i / N - Math.PI / 2),
|
||||
circular_size: Math.random(),
|
||||
circular_color: '#' + (
|
||||
Math.floor(Math.random() * 16777215).toString(16) + '000000'
|
||||
).substr(0, 6),
|
||||
grid_x: i % L,
|
||||
grid_y: Math.floor(i / L),
|
||||
grid_size: 1,
|
||||
grid_color: '#ccc'
|
||||
};
|
||||
|
||||
['x', 'y', 'size', 'color'].forEach(function(val) {
|
||||
o[val] = o['grid_' + val];
|
||||
});
|
||||
|
||||
g.nodes.push(o);
|
||||
}
|
||||
|
||||
for (i = 0; i < E; i++)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: 'n' + (Math.random() * N | 0),
|
||||
target: 'n' + (Math.random() * N | 0)
|
||||
});
|
||||
|
||||
// Instantiate sigma:
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
container: 'graph-container',
|
||||
settings: {
|
||||
animationsTime: 1000
|
||||
}
|
||||
});
|
||||
|
||||
setInterval(function() {
|
||||
var prefix = ['grid_', 'circular_'][step = +!step];
|
||||
sigma.plugins.animate(
|
||||
s,
|
||||
{
|
||||
x: prefix + 'x',
|
||||
y: prefix + 'y',
|
||||
size: prefix + 'size',
|
||||
color: prefix + 'color'
|
||||
}
|
||||
);
|
||||
}, 2000);
|
||||
</script>
|
|
@ -0,0 +1,202 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.layout.forceAtlas2/worker.js"></script>
|
||||
<script src="../plugins/sigma.layout.forceAtlas2/supervisor.js"></script>
|
||||
<div id="container">
|
||||
<style>
|
||||
#webgl {
|
||||
top: 0;
|
||||
bottom: 50%;
|
||||
left: 0;
|
||||
right: 50%;
|
||||
color: #fff;
|
||||
background: #000;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#canvas2 {
|
||||
top: 50%;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 50%;
|
||||
color: #000;
|
||||
background: #eee;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#canvas1 {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
right: 0;
|
||||
color: #000;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.label {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 1;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
</style>
|
||||
<div id="webgl">
|
||||
<div class="label">WebGL renderer + Camera 1</div>
|
||||
</div>
|
||||
<div id="canvas1">
|
||||
<div class="label">Canvas renderer + Camera 2</div>
|
||||
</div>
|
||||
<div id="canvas2">
|
||||
<div class="label">Canvas renderer + Camera 1</div>
|
||||
</div>
|
||||
</div>
|
||||
<script id="example-content">
|
||||
/**
|
||||
* This example spawns three different renderers, two of them sharing
|
||||
* their camera. Also, a ForceAtlas2 runs on the graph.
|
||||
*
|
||||
* It is basically a mashup between some other examples, to show how
|
||||
* sigma behaves when instantiated in a weird and heavy configuration.
|
||||
*/
|
||||
|
||||
var i,
|
||||
s,
|
||||
o,
|
||||
N = 100,
|
||||
E = 500,
|
||||
C = 5,
|
||||
d = 0.5,
|
||||
cs = [],
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
};
|
||||
|
||||
for (i = 0; i < C; i++)
|
||||
cs.push({
|
||||
id: i,
|
||||
nodes: [],
|
||||
color: '#' + (
|
||||
Math.floor(Math.random() * 16777215).toString(16) + '000000'
|
||||
).substr(0, 6)
|
||||
});
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
o = cs[(Math.random() * C) | 0];
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node' + i,
|
||||
x: Math.cos(2 * i * Math.PI / N),
|
||||
y: Math.sin(2 * i * Math.PI / N),
|
||||
size: 0.5 + 4.5 * Math.random(),
|
||||
color: o.color
|
||||
});
|
||||
o.nodes.push('n' + i);
|
||||
}
|
||||
|
||||
for (i = 0; i < E; i++) {
|
||||
if (Math.random() < 1 - d)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
size: 0.5,
|
||||
source: 'n' + ((Math.random() * N) | 0),
|
||||
target: 'n' + ((Math.random() * N) | 0)
|
||||
});
|
||||
else {
|
||||
o = cs[(Math.random() * C) | 0]
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
size: 0.5,
|
||||
source: o.nodes[(Math.random() * o.nodes.length) | 0],
|
||||
target: o.nodes[(Math.random() * o.nodes.length) | 0]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
settings: {
|
||||
skipErrors: true
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize cameras:
|
||||
s.addCamera('cam1'),
|
||||
s.addCamera('cam2');
|
||||
|
||||
// Initialize the three renderers:
|
||||
s.addRenderer({
|
||||
container: document.getElementById('webgl'),
|
||||
type: 'webgl',
|
||||
camera: 'cam1',
|
||||
settings: {
|
||||
defaultLabelColor: '#fff'
|
||||
}
|
||||
});
|
||||
|
||||
s.addRenderer({
|
||||
container: document.getElementById('canvas2'),
|
||||
type: 'canvas',
|
||||
camera: 'cam1',
|
||||
settings: {
|
||||
drawEdges: false
|
||||
}
|
||||
});
|
||||
|
||||
s.addRenderer({
|
||||
container: document.getElementById('canvas1'),
|
||||
type: 'canvas',
|
||||
camera: 'cam2'
|
||||
});
|
||||
|
||||
// Start the layout algorithm:
|
||||
s.startForceAtlas2();
|
||||
</script>
|
|
@ -0,0 +1,104 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This is a basic example on how to instantiate sigma. A random graph is
|
||||
* generated and stored in the "graph" variable, and then sigma is instantiated
|
||||
* directly with the graph.
|
||||
*
|
||||
* The simple instance of sigma is enough to make it render the graph on the on
|
||||
* the screen, since the graph is given directly to the constructor.
|
||||
*/
|
||||
var i,
|
||||
s,
|
||||
N = 100,
|
||||
E = 500,
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
};
|
||||
|
||||
// Generate a random graph:
|
||||
for (i = 0; i < N; i++)
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: Math.random(),
|
||||
color: '#666'
|
||||
});
|
||||
|
||||
for (i = 0; i < E; i++)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: 'n' + (Math.random() * N | 0),
|
||||
target: 'n' + (Math.random() * N | 0),
|
||||
size: Math.random(),
|
||||
color: '#ccc'
|
||||
});
|
||||
|
||||
// Instantiate sigma:
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
container: 'graph-container'
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,164 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script src="../plugins/sigma.layout.forceAtlas2/worker.js"></script>
|
||||
<script src="../plugins/sigma.layout.forceAtlas2/supervisor.js"></script>
|
||||
<script>
|
||||
/**
|
||||
* This is a basic example on how to develop a custom edge renderer. In
|
||||
* this example, the renderer will display the edge as a path made of two
|
||||
* segments, an horizontal one and a vertical one. To make it just a bit
|
||||
* "more readable", I also used the FA2 plugin (but it is actually still
|
||||
* not readable).
|
||||
*
|
||||
* IMPORTANT: This edge renderer just works with the canvas renderer. If
|
||||
* you do want to display images with the WebGL renderer, you will have
|
||||
* to develop a specific WebGL edge renderer.
|
||||
*/
|
||||
sigma.utils.pkg('sigma.canvas.edges');
|
||||
sigma.canvas.edges.t = function(edge, source, target, context, settings) {
|
||||
var color = edge.color,
|
||||
prefix = settings('prefix') || '',
|
||||
edgeColor = settings('edgeColor'),
|
||||
defaultNodeColor = settings('defaultNodeColor'),
|
||||
defaultEdgeColor = settings('defaultEdgeColor');
|
||||
|
||||
if (!color)
|
||||
switch (edgeColor) {
|
||||
case 'source':
|
||||
color = source.color || defaultNodeColor;
|
||||
break;
|
||||
case 'target':
|
||||
color = target.color || defaultNodeColor;
|
||||
break;
|
||||
default:
|
||||
color = defaultEdgeColor;
|
||||
break;
|
||||
}
|
||||
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = edge[prefix + 'size'] || 1;
|
||||
context.beginPath();
|
||||
context.moveTo(
|
||||
source[prefix + 'x'],
|
||||
source[prefix + 'y']
|
||||
);
|
||||
context.lineTo(
|
||||
source[prefix + 'x'],
|
||||
target[prefix + 'y']
|
||||
);
|
||||
context.lineTo(
|
||||
target[prefix + 'x'],
|
||||
target[prefix + 'y']
|
||||
);
|
||||
context.stroke();
|
||||
};
|
||||
|
||||
// Now, let's use the renderer
|
||||
var i,
|
||||
s,
|
||||
N = 50,
|
||||
E = 150,
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
},
|
||||
colors = [
|
||||
'#617db4',
|
||||
'#668f3c',
|
||||
'#c6583e',
|
||||
'#b956af'
|
||||
];
|
||||
|
||||
// Generate a random graph:
|
||||
for (i = 0; i < N; i++)
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: Math.random(),
|
||||
color: colors[Math.floor(Math.random() * colors.length)]
|
||||
});
|
||||
|
||||
for (i = 0; i < E; i++)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: 'n' + (Math.random() * N | 0),
|
||||
target: 'n' + (Math.random() * N | 0),
|
||||
size: Math.random(),
|
||||
type: 't'
|
||||
});
|
||||
|
||||
// Instantiate sigma:
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
renderer: {
|
||||
// IMPORTANT:
|
||||
// This works only with the canvas renderer, so the
|
||||
// renderer type set as "canvas" is necessary here.
|
||||
container: 'graph-container',
|
||||
type: 'canvas'
|
||||
}
|
||||
});
|
||||
|
||||
// Start the ForceAtlas2 algorithm:
|
||||
s.startForceAtlas2();
|
||||
</script>
|
|
@ -0,0 +1,239 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This is a basic example on how to develop a custom node renderer. In
|
||||
* this example, the renderer will display an image clipped in a disc,
|
||||
* with a border colored according the node's "color" value.
|
||||
*
|
||||
* If a node as the value "image" to its attribute "type", then it will
|
||||
* displayed with the node renderer "sigma.canvas.nodes.image", with the
|
||||
* url being its "url" value.
|
||||
*
|
||||
* IMPORTANT: This node renderer just works with the canvas renderer. If
|
||||
* you do want to display images with the WebGL renderer, you will have
|
||||
* to develop a specific WebGL node renderer.
|
||||
*/
|
||||
sigma.utils.pkg('sigma.canvas.nodes');
|
||||
sigma.canvas.nodes.image = (function() {
|
||||
var _cache = {},
|
||||
_loading = {},
|
||||
_callbacks = {};
|
||||
|
||||
// Return the renderer itself:
|
||||
var renderer = function(node, context, settings) {
|
||||
var args = arguments,
|
||||
prefix = settings('prefix') || '',
|
||||
size = node[prefix + 'size'],
|
||||
color = node.color || settings('defaultNodeColor'),
|
||||
url = node.url;
|
||||
|
||||
if (_cache[url]) {
|
||||
context.save();
|
||||
|
||||
// Draw the clipping disc:
|
||||
context.beginPath();
|
||||
context.arc(
|
||||
node[prefix + 'x'],
|
||||
node[prefix + 'y'],
|
||||
node[prefix + 'size'],
|
||||
0,
|
||||
Math.PI * 2,
|
||||
true
|
||||
);
|
||||
context.closePath();
|
||||
context.clip();
|
||||
|
||||
// Draw the image
|
||||
context.drawImage(
|
||||
_cache[url],
|
||||
node[prefix + 'x'] - size,
|
||||
node[prefix + 'y'] - size,
|
||||
2 * size,
|
||||
2 * size
|
||||
);
|
||||
|
||||
// Quit the "clipping mode":
|
||||
context.restore();
|
||||
|
||||
// Draw the border:
|
||||
context.beginPath();
|
||||
context.arc(
|
||||
node[prefix + 'x'],
|
||||
node[prefix + 'y'],
|
||||
node[prefix + 'size'],
|
||||
0,
|
||||
Math.PI * 2,
|
||||
true
|
||||
);
|
||||
context.lineWidth = size / 5;
|
||||
context.strokeStyle = node.color || settings('defaultNodeColor');
|
||||
context.stroke();
|
||||
} else {
|
||||
sigma.canvas.nodes.image.cache(url);
|
||||
sigma.canvas.nodes.def.apply(
|
||||
sigma.canvas.nodes,
|
||||
args
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Let's add a public method to cache images, to make it possible to
|
||||
// preload images before the initial rendering:
|
||||
renderer.cache = function(url, callback) {
|
||||
if (callback)
|
||||
_callbacks[url] = callback;
|
||||
|
||||
if (_loading[url])
|
||||
return;
|
||||
|
||||
var img = new Image();
|
||||
|
||||
img.onload = function() {
|
||||
_loading[url] = false;
|
||||
_cache[url] = img;
|
||||
|
||||
if (_callbacks[url]) {
|
||||
_callbacks[url].call(this, img);
|
||||
delete _callbacks[url];
|
||||
}
|
||||
};
|
||||
|
||||
_loading[url] = true;
|
||||
img.src = url;
|
||||
};
|
||||
|
||||
return renderer;
|
||||
})();
|
||||
|
||||
// Now that's the renderer has been implemented, let's generate a graph
|
||||
// to render:
|
||||
var i,
|
||||
s,
|
||||
img,
|
||||
N = 100,
|
||||
E = 500,
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
},
|
||||
urls = [
|
||||
'img/img1.png',
|
||||
'img/img2.png',
|
||||
'img/img3.png',
|
||||
'img/img4.png'
|
||||
],
|
||||
loaded = 0,
|
||||
colors = [
|
||||
'#617db4',
|
||||
'#668f3c',
|
||||
'#c6583e',
|
||||
'#b956af'
|
||||
];
|
||||
|
||||
// Generate a random graph, with ~30% nodes having the type "image":
|
||||
for (i = 0; i < N; i++) {
|
||||
img = Math.random() >= 0.7;
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
type: img ? 'image' : 'def',
|
||||
url: img ? urls[Math.floor(Math.random() * urls.length)] : null,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: Math.random(),
|
||||
color: colors[Math.floor(Math.random() * colors.length)]
|
||||
});
|
||||
}
|
||||
|
||||
for (i = 0; i < E; i++)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: 'n' + (Math.random() * N | 0),
|
||||
target: 'n' + (Math.random() * N | 0),
|
||||
size: Math.random()
|
||||
});
|
||||
|
||||
// Then, wait for all images to be loaded before instanciating sigma:
|
||||
urls.forEach(function(url) {
|
||||
sigma.canvas.nodes.image.cache(
|
||||
url,
|
||||
function() {
|
||||
if (++loaded === urls.length)
|
||||
// Instantiate sigma:
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
renderer: {
|
||||
// IMPORTANT:
|
||||
// This works only with the canvas renderer, so the
|
||||
// renderer type set as "canvas" is necessary here.
|
||||
container: document.getElementById('graph-container'),
|
||||
type: 'canvas'
|
||||
},
|
||||
settings: {
|
||||
minNodeSize: 8,
|
||||
maxNodeSize: 16,
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
</script>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
{"nodes":[{"id":"n1","label":"n1","latitude":50.93,"longitude":2.48,"size":"5.5","color":"rgb(1,179,255)"},{"id":"n2","label":"n2","latitude":50.88,"longitude":2.0,"size":"5.0","color":"rgb(1,179,255)"},{"id":"n4","label":"n4","latitude":49.4,"longitude":0.19,"size":"6.0","color":"rgb(1,179,255)"},{"id":"n5","label":"n5","latitude":48.49,"longitude":-1.92,"size":"6.0","color":"rgb(1,179,255)"},{"id":"n6","label":"n6","latitude":48.26,"longitude":-4.38,"size":"4.5","color":"rgb(1,179,255)"},{"id":"n7","label":"n7","latitude":47.15,"longitude":-2.09,"size":"6.5","color":"rgb(1,179,255)"},{"id":"n8","label":"n8","latitude":46.02,"longitude":-1.04,"size":"6.5","color":"rgb(1,179,255)"},{"id":"n9","label":"n9","latitude":43.22,"longitude":-1.85,"size":"5.0","color":"rgb(1,179,255)"},{"id":"n10","label":"n10","latitude":42.38,"longitude":3.18,"size":"4.0","color":"rgb(1,179,255)"},{"id":"n11","label":"n11","latitude":43.47,"longitude":4.04,"size":"5.5","color":"rgb(1,179,255)"},{"id":"n12","label":"n12","latitude":42.9,"longitude":6.59,"size":"5.0","color":"rgb(1,179,255)"},{"id":"n13","label":"n13","latitude":43.62,"longitude":7.66,"size":"6.0","color":"rgb(1,179,255)"},{"id":"n14","label":"n14","latitude":46.05,"longitude":6.19,"size":"6.5","color":"rgb(1,179,255)"},{"id":"n15","label":"n15","latitude":47.43,"longitude":7.65,"size":"6.0","color":"rgb(1,179,255)"},{"id":"n16","label":"n16","latitude":48.9,"longitude":8.32,"size":"5.5","color":"rgb(1,179,255)"},{"id":"n17","label":"n17","latitude":49.83,"longitude":4.94,"size":"6.5","color":"rgb(1,179,255)"},{"id":"Paris","label":"Paris","latitude":48.72,"longitude":2.46,"size":"9.0","color":"rgb(1,179,255)"}],"edges":[{"id":"8","source":"n1","target":"Paris"},{"id":"7","source":"n2","target":"n4"},{"id":"28","source":"n4","target":"n1"},{"id":"30","source":"n4","target":"n7"},{"id":"26","source":"n5","target":"n1"},{"id":"27","source":"n5","target":"n2"},{"id":"0","source":"n6","target":"n5"},{"id":"29","source":"n7","target":"n5"},{"id":"1","source":"n7","target":"n8"},{"id":"17","source":"n7","target":"Paris"},{"id":"10","source":"n8","target":"n13"},{"id":"18","source":"n8","target":"Paris"},{"id":"15","source":"n9","target":"n8"},{"id":"34","source":"n10","target":"n9"},{"id":"31","source":"n10","target":"n11"},{"id":"11","source":"n11","target":"n13"},{"id":"13","source":"n11","target":"n14"},{"id":"32","source":"n12","target":"n10"},{"id":"12","source":"n12","target":"n11"},{"id":"23","source":"n12","target":"n13"},{"id":"33","source":"n13","target":"n10"},{"id":"25","source":"n13","target":"n14"},{"id":"14","source":"n14","target":"n9"},{"id":"5","source":"n14","target":"n17"},{"id":"19","source":"n14","target":"Paris"},{"id":"6","source":"n15","target":"n8"},{"id":"22","source":"n15","target":"n16"},{"id":"20","source":"n15","target":"Paris"},{"id":"4","source":"n16","target":"n15"},{"id":"24","source":"n16","target":"Paris"},{"id":"9","source":"n17","target":"n7"},{"id":"21","source":"n17","target":"n17"},{"id":"2","source":"Paris","target":"n4"},{"id":"3","source":"Paris","target":"n17"},{"id":"16","source":"Paris","target":"Paris"}]}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,204 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gexf xmlns:viz="http:///www.gexf.net/1.1draft/viz" version="1.1" xmlns="http://www.gexf.net/1.1draft">
|
||||
<meta lastmodifieddate="2010-05-14+15:57">
|
||||
<creator>Gephi 0.7</creator>
|
||||
</meta>
|
||||
<graph defaultedgetype="undirected" idtype="string" type="static" backgroundx="-147.4" backgroundy="-1050.7" backgroundxratio="0.4849" backgroundyratio="0.4849">
|
||||
<attributes class="node" mode="static">
|
||||
<attribute id="latitude" title="latitude" type="float"/>
|
||||
<attribute id="longitude" title="longitude" type="float"/>
|
||||
</attributes>
|
||||
<nodes count="17">
|
||||
<node id="n1" label="n1">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="50.93"/>
|
||||
<attvalue for="longitude" value="2.48"/>
|
||||
</attvalues>
|
||||
<viz:size value="5.5"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="-2.320261" y="1036.1836" z="0.0"/>
|
||||
</node>
|
||||
<node id="n2" label="n2">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="50.88"/>
|
||||
<attvalue for="longitude" value="2.0"/>
|
||||
</attvalues>
|
||||
<viz:size value="5.0"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="-10.697842" y="1034.7998" z="0.0"/>
|
||||
</node>
|
||||
<node id="n4" label="n4">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="49.4"/>
|
||||
<attvalue for="longitude" value="0.19"/>
|
||||
</attvalues>
|
||||
<viz:size value="6.0"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="-42.2883" y="994.49225" z="0.0"/>
|
||||
</node>
|
||||
<node id="n5" label="n5">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="48.49"/>
|
||||
<attvalue for="longitude" value="-1.92"/>
|
||||
</attvalues>
|
||||
<viz:size value="6.0"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="-79.114746" y="970.3091" z="0.0"/>
|
||||
</node>
|
||||
<node id="n6" label="n6">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="48.26"/>
|
||||
<attvalue for="longitude" value="-4.38"/>
|
||||
</attvalues>
|
||||
<viz:size value="4.5"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="-122.04985" y="964.2657" z="0.0"/>
|
||||
</node>
|
||||
<node id="n7" label="n7">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="47.15"/>
|
||||
<attvalue for="longitude" value="-2.09"/>
|
||||
</attvalues>
|
||||
<viz:size value="6.5"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="-82.08181" y="935.47577" z="0.0"/>
|
||||
</node>
|
||||
<node id="n8" label="n8">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="46.02"/>
|
||||
<attvalue for="longitude" value="-1.04"/>
|
||||
</attvalues>
|
||||
<viz:size value="6.5"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="-63.75585" y="906.7781" z="0.0"/>
|
||||
</node>
|
||||
<node id="n9" label="n9">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="43.22"/>
|
||||
<attvalue for="longitude" value="-1.85"/>
|
||||
</attvalues>
|
||||
<viz:size value="5.0"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="-77.89302" y="838.1003" z="0.0"/>
|
||||
</node>
|
||||
<node id="n10" label="n10">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="42.38"/>
|
||||
<attvalue for="longitude" value="3.18"/>
|
||||
</attvalues>
|
||||
<viz:size value="4.0"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="9.897045" y="818.11865" z="0.0"/>
|
||||
</node>
|
||||
<node id="n11" label="n11">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="43.47"/>
|
||||
<attvalue for="longitude" value="4.04"/>
|
||||
</attvalues>
|
||||
<viz:size value="5.5"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="24.906874" y="844.1002" z="0.0"/>
|
||||
</node>
|
||||
<node id="n12" label="n12">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="42.9"/>
|
||||
<attvalue for="longitude" value="6.59"/>
|
||||
</attvalues>
|
||||
<viz:size value="5.0"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="69.41277" y="830.4562" z="0.0"/>
|
||||
</node>
|
||||
<node id="n13" label="n13">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="43.62"/>
|
||||
<attvalue for="longitude" value="7.66"/>
|
||||
</attvalues>
|
||||
<viz:size value="6.0"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="88.08779" y="847.712" z="0.0"/>
|
||||
</node>
|
||||
<node id="n14" label="n14">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="46.05"/>
|
||||
<attvalue for="longitude" value="6.19"/>
|
||||
</attvalues>
|
||||
<viz:size value="6.5"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="62.431454" y="907.5323" z="0.0"/>
|
||||
</node>
|
||||
<node id="n15" label="n15">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="47.43"/>
|
||||
<attvalue for="longitude" value="7.65"/>
|
||||
</attvalues>
|
||||
<viz:size value="6.0"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="87.91326" y="942.68054" z="0.0"/>
|
||||
</node>
|
||||
<node id="n16" label="n16">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="48.9"/>
|
||||
<attvalue for="longitude" value="8.32"/>
|
||||
</attvalues>
|
||||
<viz:size value="5.5"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="99.606964" y="981.15027" z="0.0"/>
|
||||
</node>
|
||||
<node id="n17" label="n17">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="49.83"/>
|
||||
<attvalue for="longitude" value="4.94"/>
|
||||
</attvalues>
|
||||
<viz:size value="6.5"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="40.614838" y="1006.07544" z="0.0"/>
|
||||
</node>
|
||||
<node id="Paris" label="Paris">
|
||||
<attvalues>
|
||||
<attvalue for="latitude" value="48.72"/>
|
||||
<attvalue for="longitude" value="2.46"/>
|
||||
</attvalues>
|
||||
<viz:size value="9.0"/>
|
||||
<viz:color b="1" g="179" r="255"/>
|
||||
<viz:position x="-2.6693265" y="976.3798" z="0.0"/>
|
||||
</node>
|
||||
</nodes>
|
||||
<edges count="35">
|
||||
<edge id="8" source="n1" target="Paris"/>
|
||||
<edge id="7" source="n2" target="n4"/>
|
||||
<edge id="28" source="n4" target="n1"/>
|
||||
<edge id="30" source="n4" target="n7"/>
|
||||
<edge id="26" source="n5" target="n1"/>
|
||||
<edge id="27" source="n5" target="n2"/>
|
||||
<edge id="0" source="n6" target="n5"/>
|
||||
<edge id="29" source="n7" target="n5"/>
|
||||
<edge id="1" source="n7" target="n8"/>
|
||||
<edge id="17" source="n7" target="Paris"/>
|
||||
<edge id="10" source="n8" target="n13"/>
|
||||
<edge id="18" source="n8" target="Paris"/>
|
||||
<edge id="15" source="n9" target="n8"/>
|
||||
<edge id="34" source="n10" target="n9"/>
|
||||
<edge id="31" source="n10" target="n11"/>
|
||||
<edge id="11" source="n11" target="n13"/>
|
||||
<edge id="13" source="n11" target="n14"/>
|
||||
<edge id="32" source="n12" target="n10"/>
|
||||
<edge id="12" source="n12" target="n11"/>
|
||||
<edge id="23" source="n12" target="n13"/>
|
||||
<edge id="33" source="n13" target="n10"/>
|
||||
<edge id="25" source="n13" target="n14"/>
|
||||
<edge id="14" source="n14" target="n9"/>
|
||||
<edge id="5" source="n14" target="n17"/>
|
||||
<edge id="19" source="n14" target="Paris"/>
|
||||
<edge id="6" source="n15" target="n8"/>
|
||||
<edge id="22" source="n15" target="n16"/>
|
||||
<edge id="20" source="n15" target="Paris"/>
|
||||
<edge id="4" source="n16" target="n15"/>
|
||||
<edge id="24" source="n16" target="Paris"/>
|
||||
<edge id="9" source="n17" target="n7"/>
|
||||
<edge id="21" source="n17" target="n17"/>
|
||||
<edge id="2" source="Paris" target="n4"/>
|
||||
<edge id="3" source="Paris" target="n17"/>
|
||||
<edge id="16" source="Paris" target="Paris"/>
|
||||
</edges>
|
||||
</graph>
|
||||
</gexf>
|
|
@ -0,0 +1,127 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.plugins.dragNodes/sigma.plugins.dragNodes.js"></script>
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 200px;
|
||||
height: 150px;
|
||||
position: absolute;
|
||||
background-color: #999;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
<div id="sidebar">This area is not a drop target.</div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This example shows how to use the dragNodes plugin.
|
||||
*/
|
||||
var i,
|
||||
s,
|
||||
N = 100,
|
||||
E = 500,
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
};
|
||||
|
||||
// Generate a random graph:
|
||||
for (i = 0; i < N; i++)
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: Math.random(),
|
||||
color: '#666'
|
||||
});
|
||||
|
||||
for (i = 0; i < E; i++)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: 'n' + (Math.random() * N | 0),
|
||||
target: 'n' + (Math.random() * N | 0),
|
||||
size: Math.random(),
|
||||
color: '#ccc'
|
||||
});
|
||||
// sigma.renderers.def = sigma.renderers.canvas
|
||||
// Instantiate sigma:
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
container: 'graph-container'
|
||||
});
|
||||
|
||||
// Initialize the dragNodes plugin:
|
||||
var dragListener = sigma.plugins.dragNodes(s, s.renderers[0]);
|
||||
|
||||
dragListener.bind('startdrag', function(event) {
|
||||
console.log(event);
|
||||
});
|
||||
dragListener.bind('drag', function(event) {
|
||||
console.log(event);
|
||||
});
|
||||
dragListener.bind('drop', function(event) {
|
||||
console.log(event);
|
||||
});
|
||||
dragListener.bind('dragend', function(event) {
|
||||
console.log(event);
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,112 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.renderers.edgeLabels/settings.js"></script>
|
||||
<script src="../plugins/sigma.renderers.edgeLabels/sigma.canvas.edges.labels.def.js"></script>
|
||||
<script src="../plugins/sigma.renderers.edgeLabels/sigma.canvas.edges.labels.curve.js"></script>
|
||||
<script src="../plugins/sigma.renderers.edgeLabels/sigma.canvas.edges.labels.curvedArrow.js"></script>
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This example shows the available edge label renderers for the canvas
|
||||
* renderer.
|
||||
*/
|
||||
var i,
|
||||
s,
|
||||
N = 10,
|
||||
E = 50,
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
};
|
||||
|
||||
// Generate a random graph:
|
||||
for (i = 0; i < N; i++)
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: Math.random(),
|
||||
color: '#666'
|
||||
});
|
||||
|
||||
for (i = 0; i < E; i++)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
label: 'Edge ' + i,
|
||||
source: 'n' + (Math.random() * N | 0),
|
||||
target: 'n' + (Math.random() * N | 0),
|
||||
size: Math.random(),
|
||||
color: '#ccc',
|
||||
type: ['line', 'curve', 'arrow', 'curvedArrow'][Math.random() * 4 | 0]
|
||||
});
|
||||
|
||||
// Instantiate sigma:
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
renderer: {
|
||||
container: document.getElementById('graph-container'),
|
||||
type: 'canvas'
|
||||
},
|
||||
settings: {
|
||||
edgeLabelSize: 'proportional'
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,128 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This example is a copy of "basic.html", but with event bindings after.
|
||||
* Open your browser's console to see the "click", "overNode" and
|
||||
* "outNode" events logged.
|
||||
*/
|
||||
var i,
|
||||
s,
|
||||
N = 20,
|
||||
E = 200,
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
};
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: Math.random(),
|
||||
color: '#666'
|
||||
});
|
||||
|
||||
for (i = 0; i < E; i++)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: 'n' + (Math.random() * N | 0),
|
||||
target: 'n' + (Math.random() * N | 0),
|
||||
size: Math.random(),
|
||||
type: 'curve',
|
||||
color: '#ccc',
|
||||
hover_color: '#000'
|
||||
});
|
||||
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
renderer: {
|
||||
container: document.getElementById('graph-container'),
|
||||
type: 'canvas'
|
||||
},
|
||||
settings: {
|
||||
doubleClickEnabled: false,
|
||||
minEdgeSize: 0.5,
|
||||
maxEdgeSize: 4,
|
||||
enableEdgeHovering: true,
|
||||
edgeHoverColor: 'edge',
|
||||
defaultEdgeHoverColor: '#000',
|
||||
edgeHoverSizeRatio: 1,
|
||||
edgeHoverExtremities: true,
|
||||
}
|
||||
});
|
||||
|
||||
// Bind the events:
|
||||
s.bind('overNode outNode clickNode doubleClickNode rightClickNode', function(e) {
|
||||
console.log(e.type, e.data.node.label, e.data.captor);
|
||||
});
|
||||
s.bind('overEdge outEdge clickEdge doubleClickEdge rightClickEdge', function(e) {
|
||||
console.log(e.type, e.data.edge, e.data.captor);
|
||||
});
|
||||
s.bind('clickStage', function(e) {
|
||||
console.log(e.type, e.data.captor);
|
||||
});
|
||||
s.bind('doubleClickStage rightClickStage', function(e) {
|
||||
console.log(e.type, e.data.captor);
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,288 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.parsers.gexf/gexf-parser.js"></script>
|
||||
<script src="../plugins/sigma.parsers.gexf/sigma.parsers.gexf.js"></script>
|
||||
<script src="../plugins/sigma.plugins.filter/sigma.plugins.filter.js"></script>
|
||||
<link href='http://fonts.googleapis.com/css?family=Lato:300,700' rel='stylesheet' type='text/css'>
|
||||
<div id="container">
|
||||
<style>
|
||||
body {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
font-family: Lato, sans-serif;
|
||||
}
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
#control-pane {
|
||||
top: 10px;
|
||||
/*bottom: 10px;*/
|
||||
right: 10px;
|
||||
position: absolute;
|
||||
width: 230px;
|
||||
background-color: rgb(249, 247, 237);
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.3);
|
||||
}
|
||||
#control-pane > div {
|
||||
margin: 10px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.line {
|
||||
clear: both;
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 12px 0 0 0;
|
||||
border-bottom: 1px solid #aac789;
|
||||
background: transparent;
|
||||
}
|
||||
h2, h3, h4 {
|
||||
padding: 0;
|
||||
font-variant: small-caps;
|
||||
}
|
||||
.green {
|
||||
color: #437356;
|
||||
}
|
||||
h2.underline {
|
||||
color: #437356;
|
||||
background: #f4f0e4;
|
||||
margin: 0;
|
||||
border-radius: 2px;
|
||||
padding: 8px 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
input[type=range] {
|
||||
width: 160px;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
<div id="control-pane">
|
||||
<h2 class="underline">filters</h2>
|
||||
|
||||
<div>
|
||||
<h3>min degree <span id="min-degree-val">0</span></h3>
|
||||
0 <input id="min-degree" type="range" min="0" max="0" value="0"> <span id="max-degree-value">0</span><br>
|
||||
</div>
|
||||
<div>
|
||||
<h3>node category</h3>
|
||||
<select id="node-category">
|
||||
<option value="" selected>All categories</option>
|
||||
</select>
|
||||
</div>
|
||||
<span class="line"></span>
|
||||
<div>
|
||||
<button id="reset-btn">Reset filters</button>
|
||||
<button id="export-btn">Export</button>
|
||||
</div>
|
||||
<div id="dump" class="hidden"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This is an example on how to use sigma filters plugin on a real-world graph.
|
||||
*/
|
||||
var filter;
|
||||
|
||||
/**
|
||||
* DOM utility functions
|
||||
*/
|
||||
var _ = {
|
||||
$: function (id) {
|
||||
return document.getElementById(id);
|
||||
},
|
||||
|
||||
all: function (selectors) {
|
||||
return document.querySelectorAll(selectors);
|
||||
},
|
||||
|
||||
removeClass: function(selectors, cssClass) {
|
||||
var nodes = document.querySelectorAll(selectors);
|
||||
var l = nodes.length;
|
||||
for ( i = 0 ; i < l; i++ ) {
|
||||
var el = nodes[i];
|
||||
// Bootstrap compatibility
|
||||
el.className = el.className.replace(cssClass, '');
|
||||
}
|
||||
},
|
||||
|
||||
addClass: function (selectors, cssClass) {
|
||||
var nodes = document.querySelectorAll(selectors);
|
||||
var l = nodes.length;
|
||||
for ( i = 0 ; i < l; i++ ) {
|
||||
var el = nodes[i];
|
||||
// Bootstrap compatibility
|
||||
if (-1 == el.className.indexOf(cssClass)) {
|
||||
el.className += ' ' + cssClass;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
show: function (selectors) {
|
||||
this.removeClass(selectors, 'hidden');
|
||||
},
|
||||
|
||||
hide: function (selectors) {
|
||||
this.addClass(selectors, 'hidden');
|
||||
},
|
||||
|
||||
toggle: function (selectors, cssClass) {
|
||||
var cssClass = cssClass || "hidden";
|
||||
var nodes = document.querySelectorAll(selectors);
|
||||
var l = nodes.length;
|
||||
for ( i = 0 ; i < l; i++ ) {
|
||||
var el = nodes[i];
|
||||
//el.style.display = (el.style.display != 'none' ? 'none' : '' );
|
||||
// Bootstrap compatibility
|
||||
if (-1 !== el.className.indexOf(cssClass)) {
|
||||
el.className = el.className.replace(cssClass, '');
|
||||
} else {
|
||||
el.className += ' ' + cssClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function updatePane (graph, filter) {
|
||||
// get max degree
|
||||
var maxDegree = 0,
|
||||
categories = {};
|
||||
|
||||
// read nodes
|
||||
graph.nodes().forEach(function(n) {
|
||||
maxDegree = Math.max(maxDegree, graph.degree(n.id));
|
||||
categories[n.attributes.acategory] = true;
|
||||
})
|
||||
|
||||
// min degree
|
||||
_.$('min-degree').max = maxDegree;
|
||||
_.$('max-degree-value').textContent = maxDegree;
|
||||
|
||||
// node category
|
||||
var nodecategoryElt = _.$('node-category');
|
||||
Object.keys(categories).forEach(function(c) {
|
||||
var optionElt = document.createElement("option");
|
||||
optionElt.text = c;
|
||||
nodecategoryElt.add(optionElt);
|
||||
});
|
||||
|
||||
// reset button
|
||||
_.$('reset-btn').addEventListener("click", function(e) {
|
||||
_.$('min-degree').value = 0;
|
||||
_.$('min-degree-val').textContent = '0';
|
||||
_.$('node-category').selectedIndex = 0;
|
||||
filter.undo().apply();
|
||||
_.$('dump').textContent = '';
|
||||
_.hide('#dump');
|
||||
});
|
||||
|
||||
// export button
|
||||
_.$('export-btn').addEventListener("click", function(e) {
|
||||
var chain = filter.export();
|
||||
console.log(chain);
|
||||
_.$('dump').textContent = JSON.stringify(chain);
|
||||
_.show('#dump');
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize sigma with the dataset:
|
||||
// e-Diaspora Moroccan corpus of websites
|
||||
// by Dana Diminescu & Matthieu Renault
|
||||
// http://www.e-diasporas.fr/wp/moroccan.html
|
||||
sigma.parsers.gexf('data/moroccan-ediaspora.gexf', {
|
||||
container: 'graph-container',
|
||||
settings: {
|
||||
edgeColor: 'default',
|
||||
defaultEdgeColor: '#ccc'
|
||||
}
|
||||
}, function(s) {
|
||||
// Initialize the Filter API
|
||||
filter = new sigma.plugins.filter(s);
|
||||
|
||||
updatePane(s.graph, filter);
|
||||
|
||||
function applyMinDegreeFilter(e) {
|
||||
var v = e.target.value;
|
||||
_.$('min-degree-val').textContent = v;
|
||||
|
||||
filter
|
||||
.undo('min-degree')
|
||||
.nodesBy(function(n) {
|
||||
return this.degree(n.id) >= v;
|
||||
}, 'min-degree')
|
||||
.apply();
|
||||
}
|
||||
|
||||
function applyCategoryFilter(e) {
|
||||
var c = e.target[e.target.selectedIndex].value;
|
||||
filter
|
||||
.undo('node-category')
|
||||
.nodesBy(function(n) {
|
||||
return !c.length || n.attributes.acategory === c;
|
||||
}, 'node-category')
|
||||
.apply();
|
||||
}
|
||||
|
||||
_.$('min-degree').addEventListener("input", applyMinDegreeFilter); // for Chrome and FF
|
||||
_.$('min-degree').addEventListener("change", applyMinDegreeFilter); // for IE10+, that sucks
|
||||
_.$('node-category').addEventListener("change", applyCategoryFilter);
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
|
@ -0,0 +1,136 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script src="../plugins/sigma.layout.forceAtlas2/worker.js"></script>
|
||||
<script src="../plugins/sigma.layout.forceAtlas2/supervisor.js"></script>
|
||||
<script>
|
||||
/**
|
||||
* Just a simple example to show how to use the sigma.layout.forceAtlas2
|
||||
* plugin:
|
||||
*
|
||||
* A random graph is generated, such that its nodes are separated in some
|
||||
* distinct clusters. Each cluster has its own color, and the density of
|
||||
* links is stronger inside the clusters. So, we expect the algorithm to
|
||||
* regroup the nodes of each cluster.
|
||||
*/
|
||||
var i,
|
||||
s,
|
||||
o,
|
||||
N = 1000,
|
||||
E = 5000,
|
||||
C = 5,
|
||||
d = 0.5,
|
||||
cs = [],
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
};
|
||||
|
||||
// Generate the graph:
|
||||
for (i = 0; i < C; i++)
|
||||
cs.push({
|
||||
id: i,
|
||||
nodes: [],
|
||||
color: '#' + (
|
||||
Math.floor(Math.random() * 16777215).toString(16) + '000000'
|
||||
).substr(0, 6)
|
||||
});
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
o = cs[(Math.random() * C) | 0];
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node' + i,
|
||||
x: 100 * Math.cos(2 * i * Math.PI / N),
|
||||
y: 100 * Math.sin(2 * i * Math.PI / N),
|
||||
size: Math.random(),
|
||||
color: o.color
|
||||
});
|
||||
o.nodes.push('n' + i);
|
||||
}
|
||||
|
||||
for (i = 0; i < E; i++) {
|
||||
if (Math.random() < 1 - d)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: 'n' + ((Math.random() * N) | 0),
|
||||
target: 'n' + ((Math.random() * N) | 0)
|
||||
});
|
||||
else {
|
||||
o = cs[(Math.random() * C) | 0]
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: o.nodes[(Math.random() * o.nodes.length) | 0],
|
||||
target: o.nodes[(Math.random() * o.nodes.length) | 0]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
container: 'graph-container',
|
||||
settings: {
|
||||
drawEdges: false
|
||||
}
|
||||
});
|
||||
|
||||
// Start the ForceAtlas2 algorithm:
|
||||
s.startForceAtlas2({worker: true, barnesHutOptimize: false});
|
||||
</script>
|
Binary file not shown.
After Width: | Height: | Size: 303 KiB |
Binary file not shown.
After Width: | Height: | Size: 64 KiB |
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
Binary file not shown.
After Width: | Height: | Size: 100 KiB |
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,78 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.parsers.gexf/gexf-parser.js"></script>
|
||||
<script src="../plugins/sigma.parsers.gexf/sigma.parsers.gexf.js"></script>
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* Here is just a basic example on how to properly display a graph
|
||||
* exported from Gephi in the GEXF format.
|
||||
*
|
||||
* The plugin sigma.parsers.gexf can load and parse the GEXF graph file,
|
||||
* and instantiate sigma when the graph is received.
|
||||
*
|
||||
* The object given as the second parameter is the base of the instance
|
||||
* configuration object. The plugin will just add the "graph" key to it
|
||||
* before the instanciation.
|
||||
*/
|
||||
sigma.parsers.gexf('data/arctic.gexf', {
|
||||
container: 'graph-container'
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,80 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.parsers.json/sigma.parsers.json.js"></script>
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* Here is just a basic example on how to properly display a graph
|
||||
* exported from Gephi as a JSON file, with the JSON Exporter plugin from
|
||||
* the Oxford Internet Institute:
|
||||
*
|
||||
* > https://marketplace.gephi.org/plugin/json-exporter/
|
||||
*
|
||||
* The plugin sigma.parsers.json can load and parse the JSON graph file,
|
||||
* and instantiate sigma when the graph is received.
|
||||
*
|
||||
* The object given as the second parameter is the base of the instance
|
||||
* configuration object. The plugin will just add the "graph" key to it
|
||||
* before the instanciation.
|
||||
*/
|
||||
sigma.parsers.json('data/arctic.json', {
|
||||
container: 'graph-container'
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,99 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.parsers.json/sigma.parsers.json.js"></script>
|
||||
<script src="../plugins/sigma.neo4j.cypher/sigma.neo4j.cypher.js"></script>
|
||||
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
|
||||
<script type="application/javascript">
|
||||
/**
|
||||
* Here is just a basic example on how to properly display a neo4j cypher query.
|
||||
*
|
||||
* The plugin sigma.neo4j.cypher can load a cypher query, parse the JSON response,
|
||||
* and instantiate sigma when the response is received.
|
||||
*
|
||||
* It based on the json parser (that's why its must be loaded).
|
||||
*/
|
||||
sigma.neo4j.cypher(
|
||||
{ url: 'http://localhost:7474', user: 'neo4j', password: 'admin' },
|
||||
'MATCH (n) OPTIONAL MATCH (n)-[r]->(m) RETURN n,r,m LIMIT 100',
|
||||
{ container: 'graph-container' } ,
|
||||
function(s) {
|
||||
console.log('Number of nodes :'+ s.graph.nodes().length);
|
||||
console.log('Number of edges :'+ s.graph.edges().length);
|
||||
}
|
||||
);
|
||||
|
||||
// Calling neo4j to get all its relationship type
|
||||
sigma.neo4j.getTypes(
|
||||
{ url: 'http://localhost:7474', user:'neo4j', password:'admin' },
|
||||
function(types) {
|
||||
console.log("Relationship types" + types);
|
||||
}
|
||||
);
|
||||
|
||||
// Calling neo4j to get all its node label
|
||||
sigma.neo4j.getLabels(
|
||||
{ url: 'http://localhost:7474', user:'neo4j', password:'admin' },
|
||||
function(labels) {
|
||||
console.log("Node labels" + labels);
|
||||
}
|
||||
);
|
||||
</script>
|
|
@ -0,0 +1,153 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.layout.forceAtlas2/worker.js"></script>
|
||||
<script src="../plugins/sigma.layout.forceAtlas2/supervisor.js"></script>
|
||||
<script src="../plugins/sigma.plugins.neighborhoods/sigma.plugins.neighborhoods.js"></script>
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
height: 400px;
|
||||
background: #000;
|
||||
}
|
||||
</style>
|
||||
<div class="buttons">
|
||||
<button id="toggle-layout">Stop layout</button>
|
||||
<button id="restart-camera">Restart camera</button>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This example shows how to explore the neighborhoods inside a graph,
|
||||
* with a simple example plugin.
|
||||
*
|
||||
* Basically, a graph is loaded into a kind of database mockup (the
|
||||
* sigma.plugins.neighborhoods plugin) that provides a method to retrieve
|
||||
* the neighborhood (or ego-centered network) of a specified node. Then,
|
||||
* a sigma instance will display only this graph, instead of the global
|
||||
* one.
|
||||
*
|
||||
* And also, if you are looking for an exemple of graph custom method or
|
||||
* how to use the graph model outside of sigma, this is the place.
|
||||
*/
|
||||
var s = new sigma({
|
||||
container: 'graph-container',
|
||||
settings: {
|
||||
defaultLabelColor: '#fff',
|
||||
sideMargin: 2
|
||||
}
|
||||
}),
|
||||
db = new sigma.plugins.neighborhoods();
|
||||
|
||||
document.getElementById('toggle-layout').addEventListener('click', function() {
|
||||
if ((s.supervisor || {}).running) {
|
||||
s.killForceAtlas2();
|
||||
document.getElementById('toggle-layout').innerHTML = 'Start layout';
|
||||
} else {
|
||||
s.startForceAtlas2({worker: true});
|
||||
document.getElementById('toggle-layout').innerHTML = 'Stop layout';
|
||||
}
|
||||
});
|
||||
document.getElementById('restart-camera').addEventListener('click', function() {
|
||||
s.camera.goTo({
|
||||
x: 0,
|
||||
y: 0,
|
||||
angle: 0,
|
||||
ratio: 1
|
||||
});
|
||||
});
|
||||
|
||||
db.load('data/arctic.json', function() {
|
||||
// Out function to initialize sigma on a new neighborhood:
|
||||
function refreshGraph(centerNodeId) {
|
||||
// First, let's stop the ForceAtlas2 algorithm:
|
||||
s.killForceAtlas2();
|
||||
|
||||
// Restart the camera:
|
||||
s.camera.goTo({
|
||||
x: 0,
|
||||
y: 0,
|
||||
angle: 0,
|
||||
ratio: 1
|
||||
});
|
||||
|
||||
// Empty the graph:
|
||||
s.graph.clear();
|
||||
|
||||
// Read the graph:
|
||||
s.graph.read(db.neighborhood(centerNodeId));
|
||||
|
||||
// Randomize the positions of the nodes and initialize their size:
|
||||
var i,
|
||||
nodes = s.graph.nodes(),
|
||||
len = nodes.length;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
nodes[i].x = Math.cos(Math.PI * 2 * i / len);
|
||||
nodes[i].y = Math.sin(Math.PI * 2 * i / len);
|
||||
}
|
||||
|
||||
// Refresh the display:
|
||||
s.refresh();
|
||||
|
||||
// Start the ForceAtlas2 algorithm:
|
||||
s.startForceAtlas2({worker: true});
|
||||
document.getElementById('toggle-layout').innerHTML = 'Stop layout';
|
||||
}
|
||||
|
||||
// Let's now bind this new function to the "clickNode" event:
|
||||
s.bind('clickNode', function(event) {
|
||||
if (!event.data.node.center)
|
||||
refreshGraph(event.data.node.id);
|
||||
});
|
||||
|
||||
// And finally, let's initialize the first graph:
|
||||
refreshGraph('1');
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,154 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script src="../plugins/sigma.plugins.animate/sigma.plugins.animate.js"></script>
|
||||
<script src="../plugins/sigma.layout.noverlap/sigma.layout.noverlap.js"></script>
|
||||
<script>
|
||||
/**
|
||||
* Just a simple example to show how to use the sigma.layout.noverlap
|
||||
* plugin:
|
||||
*
|
||||
* A random graph is generated. Noverlap is then run.
|
||||
*/
|
||||
var i,
|
||||
s,
|
||||
o,
|
||||
N = 5000,
|
||||
E = 500,
|
||||
C = 5,
|
||||
d = 0.5,
|
||||
cs = [],
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
};
|
||||
|
||||
// Generate the graph:
|
||||
for (i = 0; i < C; i++)
|
||||
cs.push({
|
||||
id: i,
|
||||
nodes: [],
|
||||
color: '#' + (
|
||||
Math.floor(Math.random() * 16777215).toString(16) + '000000'
|
||||
).substr(0, 6)
|
||||
});
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
o = cs[(Math.random() * C) | 0];
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node' + i,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: Math.random(),
|
||||
color: o.color
|
||||
});
|
||||
o.nodes.push('n' + i);
|
||||
}
|
||||
|
||||
for (i = 0; i < E; i++) {
|
||||
if (Math.random() < 1 - d)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: 'n' + ((Math.random() * N) | 0),
|
||||
target: 'n' + ((Math.random() * N) | 0)
|
||||
});
|
||||
else {
|
||||
o = cs[(Math.random() * C) | 0]
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: o.nodes[(Math.random() * o.nodes.length) | 0],
|
||||
target: o.nodes[(Math.random() * o.nodes.length) | 0]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
container: 'graph-container',
|
||||
settings: {
|
||||
minNodeSize: 4,
|
||||
maxNodeSize: 2,
|
||||
minEdgeSize: 1,
|
||||
maxEdgeSize: 1
|
||||
}
|
||||
});
|
||||
|
||||
// Configure the noverlap layout:
|
||||
var noverlapListener = s.configNoverlap({
|
||||
nodeMargin: 0.1,
|
||||
scaleNodes: 1.05,
|
||||
gridSize: 75,
|
||||
easing: 'quadraticInOut', // animation transition function
|
||||
duration: 10000 // animation duration. Long here for the purposes of this example only
|
||||
});
|
||||
// Bind the events:
|
||||
noverlapListener.bind('start stop interpolate', function(e) {
|
||||
console.log(e.type);
|
||||
if(e.type === 'start') {
|
||||
console.time('noverlap');
|
||||
}
|
||||
if(e.type === 'interpolate') {
|
||||
console.timeEnd('noverlap');
|
||||
}
|
||||
});
|
||||
// Start the layout:
|
||||
s.startNoverlap();
|
||||
</script>
|
|
@ -0,0 +1,111 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.renderers.parallelEdges/utils.js"></script>
|
||||
<script src="../plugins/sigma.renderers.parallelEdges/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../plugins/sigma.renderers.parallelEdges/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../plugins/sigma.renderers.parallelEdges/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../plugins/sigma.renderers.parallelEdges/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This example shows the available edge label renderers for the canvas
|
||||
* renderer.
|
||||
*/
|
||||
var i,
|
||||
s,
|
||||
N = 2,
|
||||
E = 10,
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
};
|
||||
|
||||
// Generate a random graph:
|
||||
for (i = 0; i < N; i++)
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: Math.random(),
|
||||
color: '#666'
|
||||
});
|
||||
|
||||
for (i = 0; i < E; i++)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
label: 'Edge ' + i,
|
||||
source: 'n0',
|
||||
target: 'n1',
|
||||
size: Math.random(),
|
||||
color: '#ccc',
|
||||
type: 'curvedArrow',
|
||||
count: i
|
||||
});
|
||||
|
||||
// Instantiate sigma:
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
renderer: {
|
||||
container: document.getElementById('graph-container'),
|
||||
type: 'canvas'
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,142 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.renderers.customEdgeShapes/sigma.canvas.edges.dashed.js"></script>
|
||||
<script src="../plugins/sigma.renderers.customEdgeShapes/sigma.canvas.edges.dotted.js"></script>
|
||||
<script src="../plugins/sigma.renderers.customEdgeShapes/sigma.canvas.edges.parallel.js"></script>
|
||||
<script src="../plugins/sigma.renderers.customEdgeShapes/sigma.canvas.edges.tapered.js"></script>
|
||||
<script src="../plugins/sigma.renderers.customEdgeShapes/sigma.canvas.edgehovers.dashed.js"></script>
|
||||
<script src="../plugins/sigma.renderers.customEdgeShapes/sigma.canvas.edgehovers.dotted.js"></script>
|
||||
<script src="../plugins/sigma.renderers.customEdgeShapes/sigma.canvas.edgehovers.parallel.js"></script>
|
||||
<script src="../plugins/sigma.renderers.customEdgeShapes/sigma.canvas.edgehovers.tapered.js"></script>
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script>
|
||||
// generate a random graph
|
||||
var i,
|
||||
s,
|
||||
img,
|
||||
N = 10,
|
||||
E = 50,
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
},
|
||||
urls = [
|
||||
'img/img1.png',
|
||||
'img/img2.png',
|
||||
'img/img3.png',
|
||||
'img/img4.png'
|
||||
],
|
||||
colors = [
|
||||
'#617db4',
|
||||
'#668f3c',
|
||||
'#c6583e',
|
||||
'#b956af'
|
||||
];
|
||||
|
||||
// Generate a random graph, going through the different edge shapes
|
||||
for (i = 0; i < N; i++) {
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: Math.random(),
|
||||
color: colors[Math.floor(Math.random() * colors.length)]
|
||||
});
|
||||
}
|
||||
|
||||
for (i = 0; i < E; i++) {
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: 'n' + (Math.random() * N | 0),
|
||||
target: 'n' + (Math.random() * N | 0),
|
||||
type: [
|
||||
'line',
|
||||
'curve',
|
||||
'arrow',
|
||||
'curvedArrow',
|
||||
'dashed',
|
||||
'dotted',
|
||||
'parallel',
|
||||
'tapered'
|
||||
][Math.round(Math.random()*8)],
|
||||
size: Math.random()
|
||||
});
|
||||
}
|
||||
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
renderer: {
|
||||
// IMPORTANT:
|
||||
// This works only with the canvas renderer, so the
|
||||
// renderer type set as "canvas" is necessary here.
|
||||
container: document.getElementById('graph-container'),
|
||||
type: 'canvas'
|
||||
},
|
||||
settings: {
|
||||
minNodeSize: 1,
|
||||
maxNodeSize: 10,
|
||||
minEdgeSize: 0.1,
|
||||
maxEdgeSize: 2,
|
||||
enableEdgeHovering: true,
|
||||
edgeHoverSizeRatio: 2
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,178 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.renderers.customShapes/shape-library.js"></script>
|
||||
<script src="../plugins/sigma.renderers.customShapes/sigma.renderers.customShapes.js"></script>
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* IMPORTANT: This only works with the canvas renderer. TBD in the future
|
||||
* will also support the WebGL renderer.
|
||||
*/
|
||||
sigma.utils.pkg('sigma.canvas.nodes');
|
||||
|
||||
// generate a random graph
|
||||
var i,
|
||||
s,
|
||||
img,
|
||||
N = 100,
|
||||
E = 500,
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
},
|
||||
urls = [
|
||||
'img/img1.png',
|
||||
'img/img2.png',
|
||||
'img/img3.png',
|
||||
'img/img4.png'
|
||||
],
|
||||
colors = [
|
||||
'#617db4',
|
||||
'#668f3c',
|
||||
'#c6583e',
|
||||
'#b956af'
|
||||
];
|
||||
|
||||
// Generate a random graph, going through the different shapes
|
||||
for (i = 0; i < N; i++) {
|
||||
var node = {
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
// note the ShapeLibrary.enumerate() returns the names of all
|
||||
// supported renderers
|
||||
type: ShapeLibrary.enumerate().map(function(s){return s.name;})[Math.round(Math.random()*5)],
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: Math.random(),
|
||||
color: colors[Math.floor(Math.random() * colors.length)],
|
||||
borderColor: colors[Math.floor(Math.random()* colors.length)]
|
||||
};
|
||||
|
||||
if(Math.random()>0.75 && node.type!='pacman') { // ~0.75 of the (non-pacman)shapes will have an image
|
||||
node.image = {
|
||||
url: urls[Math.floor(Math.random() * urls.length)],
|
||||
// scale/clip are ratio values applied on top of 'size'
|
||||
scale: 1.3,
|
||||
clip: 0.85
|
||||
}
|
||||
}
|
||||
|
||||
switch(node.type) {
|
||||
case "equilateral":
|
||||
node.equilateral = {
|
||||
rotate: Math.random()*45, // random rotate up to 45 deg
|
||||
numPoints: Math.round(5 + Math.random()*3)
|
||||
}
|
||||
break;
|
||||
case "star":
|
||||
node.star = {
|
||||
innerRatio: 0.4 + Math.random()*0.2,
|
||||
numPoints: Math.round(4 + Math.random()*3)
|
||||
}
|
||||
if(node.image) {
|
||||
// note clip/scale are ratio values. So we fit them to the inner ratio of the star shape
|
||||
node.image.clip = node.star.innerRatio *0.95;
|
||||
node.image.scale = node.star.innerRatio *1.2;
|
||||
}
|
||||
break;
|
||||
case "square":
|
||||
case "diamond":
|
||||
if(node.image) {
|
||||
// note clip/scale are ratio values. So we fit them to the borders of the square shape
|
||||
node.image.clip = 0.7;
|
||||
}
|
||||
break;
|
||||
case "circle":
|
||||
break;
|
||||
case "cross":
|
||||
node.cross = {
|
||||
lineWeight: Math.round(Math.random() * 5)
|
||||
}
|
||||
break;
|
||||
}
|
||||
g.nodes.push(node);
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < E; i++)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: 'n' + (Math.random() * N | 0),
|
||||
target: 'n' + (Math.random() * N | 0),
|
||||
size: Math.random()
|
||||
});
|
||||
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
renderer: {
|
||||
// IMPORTANT:
|
||||
// This works only with the canvas renderer, so the
|
||||
// renderer type set as "canvas" is necessary here.
|
||||
container: document.getElementById('graph-container'),
|
||||
type: 'canvas'
|
||||
},
|
||||
settings: {
|
||||
minNodeSize: 8,
|
||||
maxNodeSize: 16,
|
||||
}
|
||||
});
|
||||
CustomShapes.init(s);
|
||||
s.refresh();
|
||||
</script>
|
|
@ -0,0 +1,111 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.renderers.edgeDots/sigma.canvas.edges.dotCurve.js"></script>
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This example shows how the edgeDots plugin can be used to display dots
|
||||
* on the edges near the nodes in the graph.
|
||||
*/
|
||||
var i,
|
||||
s,
|
||||
N = 2,
|
||||
E = 1,
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
};
|
||||
|
||||
// Generate a random graph:
|
||||
for (i = 0; i < N; i++)
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: Math.random(),
|
||||
color: '#666'
|
||||
});
|
||||
// Some colors to use on the dots
|
||||
var colors = ["#ff0000", "#00ff00", "#0000ff"];
|
||||
for (i = 0; i < E; i++)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
label: 'Edge ' + i,
|
||||
source: 'n0',
|
||||
target: 'n1',
|
||||
size: Math.random(),
|
||||
color: '#ccc',
|
||||
type: 'curve',
|
||||
dotOffset:4,
|
||||
dotSize:1.2,
|
||||
sourceDotColor:colors[i%colors.length],
|
||||
targetDotColor:colors[(i+1)%colors.length]
|
||||
});
|
||||
|
||||
// Instantiate sigma:
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
renderer: {
|
||||
container: document.getElementById('graph-container'),
|
||||
type: 'canvas'
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,111 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.renderers.snapshot/sigma.renderers.snapshot.js"></script>
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This is a basic example on how to instantiate sigma. A random graph is
|
||||
* generated and stored in the "graph" variable, and then sigma is instantiated
|
||||
* directly with the graph.
|
||||
*
|
||||
* The simple instance of sigma is enough to make it render the graph on the on
|
||||
* the screen, since the graph is given directly to the constructor.
|
||||
*/
|
||||
var i,
|
||||
s,
|
||||
N = 100,
|
||||
E = 500,
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
};
|
||||
|
||||
// Generate a random graph:
|
||||
for (i = 0; i < N; i++)
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: Math.random(),
|
||||
color: '#666'
|
||||
});
|
||||
|
||||
for (i = 0; i < E; i++)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: 'n' + (Math.random() * N | 0),
|
||||
target: 'n' + (Math.random() * N | 0),
|
||||
size: Math.random(),
|
||||
color: '#ccc'
|
||||
});
|
||||
|
||||
// sigma.renderers.def = sigma.renderers.canvas;
|
||||
|
||||
// Instantiate sigma:
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
container: 'graph-container'
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
console.log(s.renderers[0].snapshot({format: 'png', background: 'white', filename: 'my-graph.png', labels: false}));
|
||||
}, 1000);
|
||||
</script>
|
|
@ -0,0 +1,114 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<div id="container">
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
#graph-container {
|
||||
top: 30%;
|
||||
bottom: 30%;
|
||||
left: 50px;
|
||||
right: 50px;
|
||||
position: absolute;
|
||||
background: #fff;
|
||||
}
|
||||
#container {
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 300%;
|
||||
background: #ccc;
|
||||
}
|
||||
</style>
|
||||
<div>Scroll down to see the graph</div>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This example copies basic.html, but with the sigma container somewhere in a
|
||||
* page such that the user has to scroll to manipulate it. This example is here
|
||||
* to facilitate testing sigma integration in real-life web pages.
|
||||
*/
|
||||
var i,
|
||||
s,
|
||||
N = 100,
|
||||
E = 500,
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
};
|
||||
|
||||
// Generate a random graph:
|
||||
for (i = 0; i < N; i++)
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: Math.random(),
|
||||
color: '#666'
|
||||
});
|
||||
|
||||
for (i = 0; i < E; i++)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: 'n' + (Math.random() * N | 0),
|
||||
target: 'n' + (Math.random() * N | 0),
|
||||
size: Math.random(),
|
||||
color: '#ccc'
|
||||
});
|
||||
|
||||
// Instantiate sigma:
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
container: 'graph-container'
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,152 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<div id="container">
|
||||
<style>
|
||||
#webgl {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 50%;
|
||||
color: #fff;
|
||||
background: #000;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
right: 0;
|
||||
color: #000;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.label {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 1;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
</style>
|
||||
<div id="webgl">
|
||||
<div class="label">WebGL renderer</div>
|
||||
</div>
|
||||
<div id="canvas">
|
||||
<div class="label">Canvas renderer</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This example spawns two different renderers with the same camera. When
|
||||
* the users will drag any of the renderers, it will move the other one
|
||||
* as well.
|
||||
*
|
||||
* Also, settings are different fo both renderers.
|
||||
*
|
||||
* It might look a bit useless (I prefer overkill...), but it makes
|
||||
* possible to develop renderers linked by their camera, for example to
|
||||
* implement a minimap.
|
||||
*/
|
||||
|
||||
var i,
|
||||
N = 100,
|
||||
E = 500,
|
||||
s = new sigma(),
|
||||
cam = s.addCamera();
|
||||
|
||||
// Generate a random graph:
|
||||
for (i = 0; i < N; i++)
|
||||
s.graph.addNode({
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: 4 + (3 * Math.random()) | 0
|
||||
});
|
||||
|
||||
for (i = 0; i < E; i++)
|
||||
s.graph.addEdge({
|
||||
id: 'e' + i,
|
||||
source: 'n' + (Math.random() * N | 0),
|
||||
target: 'n' + (Math.random() * N | 0),
|
||||
size: 1 + Math.random()
|
||||
});
|
||||
|
||||
// Initialize two distinct renderers, each with its own settings:
|
||||
s.addRenderer({
|
||||
container: document.getElementById('webgl'),
|
||||
type: 'webgl',
|
||||
camera: cam,
|
||||
settings: {
|
||||
defaultLabelColor: '#fff',
|
||||
defaultNodeColor: '#999',
|
||||
defaultEdgeColor: '#333',
|
||||
edgeColor: 'default'
|
||||
}
|
||||
});
|
||||
|
||||
s.addRenderer({
|
||||
container: document.getElementById('canvas'),
|
||||
type: 'canvas',
|
||||
camera: cam,
|
||||
settings: {
|
||||
batchEdgesDrawing: true,
|
||||
hideEdgesOnMove: true,
|
||||
defaultLabelColor: '#000',
|
||||
defaultNodeColor: '#666',
|
||||
defaultEdgeColor: '#999',
|
||||
edgeColor: 'default'
|
||||
}
|
||||
});
|
||||
|
||||
// Refresh the instance to refresh the new renderers:
|
||||
s.refresh();
|
||||
</script>
|
|
@ -0,0 +1,142 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.layout.forceAtlas2/worker.js"></script>
|
||||
<script src="../plugins/sigma.layout.forceAtlas2/supervisor.js"></script>
|
||||
<script src="../plugins/sigma.exporters.svg/sigma.exporters.svg.js"></script>
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
}
|
||||
#layout {
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
position: fixed;
|
||||
}
|
||||
#export {
|
||||
top: 40px;
|
||||
left: 10px;
|
||||
position: fixed;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
<button id="layout" type="button">Layout</button>
|
||||
<button id="export" type="export">Export</button>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This is a basic example on how to instantiate sigma. A random graph is
|
||||
* generated and stored in the "graph" variable, and then sigma is instantiated
|
||||
* directly with the graph.
|
||||
*
|
||||
* The simple instance of sigma is enough to make it render the graph on the on
|
||||
* the screen, since the graph is given directly to the constructor.
|
||||
*/
|
||||
var i,
|
||||
s,
|
||||
N = 200,
|
||||
E = 1000,
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
};
|
||||
|
||||
// Generate a random graph:
|
||||
for (i = 0; i < N; i++)
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: Math.random(),
|
||||
color: ['#666', '#abc', '#eee', '#ff00aa'][Math.random() * 4 | 0]
|
||||
});
|
||||
|
||||
for (i = 0; i < E; i++)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: 'n' + (Math.random() * N | 0),
|
||||
target: 'n' + (Math.random() * N | 0),
|
||||
size: Math.random(),
|
||||
color: ['#666', '#abc', '#eee', '#ff00aa'][Math.random() * 4 | 0]
|
||||
});
|
||||
|
||||
// Instantiate sigma:
|
||||
s = new sigma({
|
||||
graph: g
|
||||
});
|
||||
|
||||
// Adding a canvas renderer
|
||||
s.addRenderer({
|
||||
container: 'graph-container',
|
||||
type: 'canvas'
|
||||
});
|
||||
|
||||
s.refresh();
|
||||
|
||||
// Listeners
|
||||
var force = false;
|
||||
document.getElementById('layout').onclick = function() {
|
||||
if (!force)
|
||||
s.startForceAtlas2({slowDown: 10});
|
||||
else
|
||||
s.stopForceAtlas2();
|
||||
force = !force;
|
||||
};
|
||||
|
||||
document.getElementById('export').onclick = function() {
|
||||
console.log('exporting...');
|
||||
var output = s.toSVG({download: true, filename: 'mygraph.svg', size: 1000});
|
||||
// console.log(output);
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,166 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<script src="../plugins/sigma.plugins.neighborhoods/sigma.plugins.neighborhoods.js"></script>
|
||||
<script src="../plugins/sigma.layout.forceAtlas2/supervisor.js"></script>
|
||||
<script src="../plugins/sigma.layout.forceAtlas2/worker.js"></script>
|
||||
<script src="lib/jquery-2.1.1.min.js"></script>
|
||||
<div id="container">
|
||||
<style>
|
||||
#graph-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
background-color: #455660;
|
||||
}
|
||||
.sigma-edge {
|
||||
stroke: #14191C;
|
||||
}
|
||||
.sigma-node {
|
||||
fill: green;
|
||||
stroke: #14191C;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
.sigma-node:hover {
|
||||
fill: blue;
|
||||
}
|
||||
.muted {
|
||||
fill-opacity: 0.1;
|
||||
stroke-opacity: 0.1;
|
||||
}
|
||||
</style>
|
||||
<div id="graph-container"></div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This is a basic example of how one could spawn a freestyle svg renderer
|
||||
* to achieve his/her goal through css and jQuery to display fancy graphs
|
||||
* but somewhat less performant.
|
||||
*/
|
||||
var i,
|
||||
s,
|
||||
N = 100,
|
||||
E = 500,
|
||||
g = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
};
|
||||
|
||||
// Generate a random graph:
|
||||
for (i = 0; i < N; i++)
|
||||
g.nodes.push({
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: Math.random(),
|
||||
color: '#666'
|
||||
});
|
||||
|
||||
for (i = 0; i < E; i++)
|
||||
g.edges.push({
|
||||
id: 'e' + i,
|
||||
source: 'n' + (Math.random() * N | 0),
|
||||
target: 'n' + (Math.random() * N | 0),
|
||||
size: Math.random(),
|
||||
color: '#ccc'
|
||||
});
|
||||
|
||||
// Instantiate sigma:
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
settings: {
|
||||
enableHovering: false
|
||||
}
|
||||
});
|
||||
|
||||
s.addRenderer({
|
||||
id: 'main',
|
||||
type: 'svg',
|
||||
container: document.getElementById('graph-container'),
|
||||
freeStyle: true
|
||||
});
|
||||
|
||||
s.refresh();
|
||||
|
||||
// Binding silly interactions
|
||||
function mute(node) {
|
||||
if (!~node.getAttribute('class').search(/muted/))
|
||||
node.setAttributeNS(null, 'class', node.getAttribute('class') + ' muted');
|
||||
}
|
||||
|
||||
function unmute(node) {
|
||||
node.setAttributeNS(null, 'class', node.getAttribute('class').replace(/(\s|^)muted(\s|$)/g, '$2'));
|
||||
}
|
||||
|
||||
$('.sigma-node').click(function() {
|
||||
|
||||
// Muting
|
||||
$('.sigma-node, .sigma-edge').each(function() {
|
||||
mute(this);
|
||||
});
|
||||
|
||||
// Unmuting neighbors
|
||||
var neighbors = s.graph.neighborhood($(this).attr('data-node-id'));
|
||||
neighbors.nodes.forEach(function(node) {
|
||||
unmute($('[data-node-id="' + node.id + '"]')[0]);
|
||||
});
|
||||
|
||||
neighbors.edges.forEach(function(edge) {
|
||||
unmute($('[data-edge-id="' + edge.id + '"]')[0]);
|
||||
});
|
||||
});
|
||||
|
||||
s.bind('clickStage', function() {
|
||||
$('.sigma-node, .sigma-edge').each(function() {
|
||||
unmute(this);
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,150 @@
|
|||
<!-- START SIGMA IMPORTS -->
|
||||
<script src="../src/sigma.core.js"></script>
|
||||
<script src="../src/conrad.js"></script>
|
||||
<script src="../src/utils/sigma.utils.js"></script>
|
||||
<script src="../src/utils/sigma.polyfills.js"></script>
|
||||
<script src="../src/sigma.settings.js"></script>
|
||||
<script src="../src/classes/sigma.classes.dispatcher.js"></script>
|
||||
<script src="../src/classes/sigma.classes.configurable.js"></script>
|
||||
<script src="../src/classes/sigma.classes.graph.js"></script>
|
||||
<script src="../src/classes/sigma.classes.camera.js"></script>
|
||||
<script src="../src/classes/sigma.classes.quad.js"></script>
|
||||
<script src="../src/classes/sigma.classes.edgequad.js"></script>
|
||||
<script src="../src/captors/sigma.captors.mouse.js"></script>
|
||||
<script src="../src/captors/sigma.captors.touch.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.canvas.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.webgl.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.svg.js"></script>
|
||||
<script src="../src/renderers/sigma.renderers.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.nodes.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.def.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.fast.js"></script>
|
||||
<script src="../src/renderers/webgl/sigma.webgl.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.labels.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.hovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.nodes.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.def.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curve.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.arrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js"></script>
|
||||
<script src="../src/renderers/canvas/sigma.canvas.extremities.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.utils.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.nodes.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.edges.curve.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.labels.def.js"></script>
|
||||
<script src="../src/renderers/svg/sigma.svg.hovers.def.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.rescale.js"></script>
|
||||
<script src="../src/middlewares/sigma.middlewares.copy.js"></script>
|
||||
<script src="../src/misc/sigma.misc.animation.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.bindDOMEvents.js"></script>
|
||||
<script src="../src/misc/sigma.misc.drawHovers.js"></script>
|
||||
<!-- END SIGMA IMPORTS -->
|
||||
<div id="container">
|
||||
<style>
|
||||
#svg {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 50%;
|
||||
color: #fff;
|
||||
background: #000;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
right: 0;
|
||||
color: #000;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.label {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 1;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
</style>
|
||||
<div id="svg">
|
||||
<div class="label">SVG renderer</div>
|
||||
</div>
|
||||
<div id="canvas">
|
||||
<div class="label">Canvas renderer</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
/**
|
||||
* This is a basic example of how a classic svg renderer renders the exact same way
|
||||
* than its canvas counterparts.
|
||||
*/
|
||||
|
||||
var i,
|
||||
N = 100,
|
||||
E = 500,
|
||||
s = new sigma(),
|
||||
cam = s.addCamera();
|
||||
|
||||
// Generate a random graph:
|
||||
for (i = 0; i < N; i++)
|
||||
s.graph.addNode({
|
||||
id: 'n' + i,
|
||||
label: 'Node ' + i,
|
||||
x: Math.random(),
|
||||
y: Math.random(),
|
||||
size: 4 + (3 * Math.random()) | 0
|
||||
});
|
||||
|
||||
for (i = 0; i < E; i++)
|
||||
s.graph.addEdge({
|
||||
id: 'e' + i,
|
||||
source: 'n' + (Math.random() * N | 0),
|
||||
target: 'n' + (Math.random() * N | 0),
|
||||
size: 1 + Math.random()
|
||||
});
|
||||
|
||||
// Initialize two distinct renderers, each with its own settings:
|
||||
s.addRenderer({
|
||||
container: document.getElementById('svg'),
|
||||
type: 'svg',
|
||||
camera: cam,
|
||||
settings: {
|
||||
hideEdgesOnMove: true,
|
||||
defaultLabelColor: '#fff',
|
||||
defaultNodeColor: '#999',
|
||||
defaultEdgeColor: '#333',
|
||||
edgeColor: 'default'
|
||||
}
|
||||
});
|
||||
|
||||
s.addRenderer({
|
||||
container: document.getElementById('canvas'),
|
||||
type: 'canvas',
|
||||
camera: cam,
|
||||
settings: {
|
||||
batchEdgesDrawing: true,
|
||||
hideEdgesOnMove: true,
|
||||
defaultLabelColor: '#000',
|
||||
defaultNodeColor: '#666',
|
||||
defaultEdgeColor: '#999',
|
||||
edgeColor: 'default'
|
||||
}
|
||||
});
|
||||
|
||||
// s.bind(s.events, function(e) {
|
||||
// console.log(e);
|
||||
// });
|
||||
|
||||
// Refresh the instance to refresh the new renderers:
|
||||
s.refresh();
|
||||
</script>
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"name": "sigma",
|
||||
"version": "1.2.1",
|
||||
"description": "A JavaScript library dedicated to graph drawing.",
|
||||
"homepage": "http://sigmajs.org",
|
||||
"bugs": "http://github.com/jacomyal/sigma.js/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/jacomyal/sigma.js.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "build/sigma.require.js",
|
||||
"devDependencies": {
|
||||
"grunt-cli": "^0.1.13",
|
||||
"grunt": "~0.4.5",
|
||||
"grunt-contrib-qunit": "~0.5.2",
|
||||
"grunt-contrib-uglify": "~0.5.1",
|
||||
"grunt-closure-linter": "~0.1.4",
|
||||
"grunt-contrib-jshint": "~0.10.0",
|
||||
"grunt-contrib-concat": "~0.5.0",
|
||||
"load-grunt-tasks": "~0.6.0",
|
||||
"grunt-sed": "~0.1.1",
|
||||
"grunt-zip": "~0.15.0",
|
||||
"http-server": "~0.9.0",
|
||||
"grunt-grunt": "^0.2.2",
|
||||
"uglify-js": "^2.4.15"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "http-server -p 8000",
|
||||
"test": "grunt travis",
|
||||
"build": "grunt build",
|
||||
"prepublish": "grunt npmPrePublish"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
sigma.exporters.svg
|
||||
========================
|
||||
|
||||
Plugin by [Guillaume Plique](https://github.com/Yomguithereal).
|
||||
|
||||
---
|
||||
|
||||
This plugin aims at providing an easy way to export a graph as a SVG file.
|
||||
|
||||
*Basic usage*
|
||||
|
||||
```js
|
||||
// Retrieving the svg file as a string
|
||||
var svgString = sigInst.toSVG();
|
||||
|
||||
// Dowload the svg file
|
||||
sigInst.toSVG({download: true, filename: 'my-fancy-graph.svg'});
|
||||
```
|
||||
|
||||
*Complex usage*
|
||||
|
||||
```js
|
||||
sigInst.toSVG({
|
||||
labels: true,
|
||||
classes: false,
|
||||
data: true,
|
||||
download: true,
|
||||
filename: 'hello.svg'
|
||||
});
|
||||
```
|
||||
|
||||
*Parameters*
|
||||
|
||||
* **size** *?integer* [`1000`]: size of the svg canvas in pixels.
|
||||
* **height** *?integer* [`1000`]: height of the svg canvas in pixels (useful only if you want a height different from the width).
|
||||
* **width** *?integer* [`1000`]: width of the svg canvas in pixels (useful only if you want a width different from the height).
|
||||
* **classes** *?boolean* [`true`]: should the exporter try to optimize the svg document by creating classes?
|
||||
* **labels** *?boolean* [`false`]: should the labels be included in the svg file?
|
||||
* **data** *?boolean* [`false`]: should additional data (node ids for instance) be included in the svg file?
|
||||
* **download** *?boolean* [`false`]: should the exporter make the browser download the svg file?
|
||||
* **filename** *?string* [`'graph.svg'`]: filename of the file to download.
|
|
@ -0,0 +1,225 @@
|
|||
;(function(undefined) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Sigma SVG Exporter
|
||||
* ===================
|
||||
*
|
||||
* This plugin is designed to export a graph to a svg file that can be
|
||||
* downloaded or just used elsewhere.
|
||||
*
|
||||
* Author: Guillaume Plique (Yomguithereal)
|
||||
* Version: 0.0.1
|
||||
*/
|
||||
|
||||
// Terminating if sigma were not to be found
|
||||
if (typeof sigma === 'undefined')
|
||||
throw 'sigma.renderers.snapshot: sigma not in scope.';
|
||||
|
||||
|
||||
/**
|
||||
* Polyfills
|
||||
*/
|
||||
var URL = this.URL || this.webkitURL || this;
|
||||
|
||||
|
||||
/**
|
||||
* Utilities
|
||||
*/
|
||||
function createBlob(data) {
|
||||
return new Blob(
|
||||
[data],
|
||||
{type: 'image/svg+xml;charset=utf-8'}
|
||||
);
|
||||
}
|
||||
|
||||
function download(string, filename) {
|
||||
|
||||
// Creating blob href
|
||||
var blob = createBlob(string);
|
||||
|
||||
// Anchor
|
||||
var o = {};
|
||||
o.anchor = document.createElement('a');
|
||||
o.anchor.setAttribute('href', URL.createObjectURL(blob));
|
||||
o.anchor.setAttribute('download', filename);
|
||||
|
||||
// Click event
|
||||
var event = document.createEvent('MouseEvent');
|
||||
event.initMouseEvent('click', true, false, window, 0, 0, 0 ,0, 0,
|
||||
false, false, false, false, 0, null);
|
||||
|
||||
URL.revokeObjectURL(blob);
|
||||
|
||||
o.anchor.dispatchEvent(event);
|
||||
delete o.anchor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Defaults
|
||||
*/
|
||||
var DEFAULTS = {
|
||||
size: '1000',
|
||||
width: '1000',
|
||||
height: '1000',
|
||||
classes: true,
|
||||
labels: true,
|
||||
data: false,
|
||||
download: false,
|
||||
filename: 'graph.svg'
|
||||
};
|
||||
|
||||
var XMLNS = 'http://www.w3.org/2000/svg';
|
||||
|
||||
|
||||
/**
|
||||
* Subprocesses
|
||||
*/
|
||||
function optimize(svg, prefix, params) {
|
||||
var nodeColorIndex = {},
|
||||
edgeColorIndex = {},
|
||||
count = 0,
|
||||
color,
|
||||
style,
|
||||
styleText = '',
|
||||
f,
|
||||
i,
|
||||
l;
|
||||
|
||||
// Creating style tag if needed
|
||||
if (params.classes) {
|
||||
style = document.createElementNS(XMLNS, 'style');
|
||||
style.setAttribute('type', 'text/css')
|
||||
svg.insertBefore(style, svg.firstChild);
|
||||
}
|
||||
|
||||
// Iterating over nodes
|
||||
var nodes = svg.querySelectorAll('[id="' + prefix + '-group-nodes"] > [class="' + prefix + '-node"]');
|
||||
|
||||
for (i = 0, l = nodes.length, f = true; i < l; i++) {
|
||||
color = nodes[i].getAttribute('fill');
|
||||
|
||||
if (!params.data)
|
||||
nodes[i].removeAttribute('data-node-id');
|
||||
|
||||
if (params.classes) {
|
||||
|
||||
if (!(color in nodeColorIndex)) {
|
||||
nodeColorIndex[color] = (f ? prefix + '-node' : 'c-' + (count++));
|
||||
styleText += '.' + nodeColorIndex[color] + '{fill: ' + color + '}';
|
||||
}
|
||||
|
||||
if (nodeColorIndex[color] !== prefix + '-node')
|
||||
nodes[i].setAttribute('class', nodes[i].getAttribute('class') + ' ' + nodeColorIndex[color]);
|
||||
nodes[i].removeAttribute('fill');
|
||||
}
|
||||
|
||||
f = false;
|
||||
}
|
||||
|
||||
// Iterating over edges
|
||||
var edges = svg.querySelectorAll('[id="' + prefix + '-group-edges"] > [class="' + prefix + '-edge"]');
|
||||
|
||||
for (i = 0, l = edges.length, f = true; i < l; i++) {
|
||||
color = edges[i].getAttribute('stroke');
|
||||
|
||||
if (!params.data)
|
||||
edges[i].removeAttribute('data-edge-id');
|
||||
|
||||
if (params.classes) {
|
||||
|
||||
if (!(color in edgeColorIndex)) {
|
||||
edgeColorIndex[color] = (f ? prefix + '-edge' : 'c-' + (count++));
|
||||
styleText += '.' + edgeColorIndex[color] + '{stroke: ' + color + '}';
|
||||
}
|
||||
|
||||
if (edgeColorIndex[color] !== prefix + '-edge')
|
||||
edges[i].setAttribute('class', edges[i].getAttribute('class') + ' ' + edgeColorIndex[color]);
|
||||
edges[i].removeAttribute('stroke');
|
||||
}
|
||||
|
||||
f = false;
|
||||
}
|
||||
|
||||
if (params.classes)
|
||||
style.appendChild(document.createTextNode(styleText));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extending prototype
|
||||
*/
|
||||
sigma.prototype.toSVG = function(params) {
|
||||
params = params || {};
|
||||
|
||||
var prefix = this.settings('classPrefix'),
|
||||
w = params.size || params.width || DEFAULTS.size,
|
||||
h = params.size || params.height || DEFAULTS.size;
|
||||
|
||||
// Creating a dummy container
|
||||
var container = document.createElement('div');
|
||||
container.setAttribute('width', w);
|
||||
container.setAttribute('height', h);
|
||||
container.setAttribute('style', 'position:absolute; top: 0px; left:0px; width: ' + w + 'px; height: ' + h + 'px;');
|
||||
|
||||
// Creating a camera
|
||||
var camera = this.addCamera();
|
||||
|
||||
// Creating a svg renderer
|
||||
var renderer = this.addRenderer({
|
||||
camera: camera,
|
||||
container: container,
|
||||
type: 'svg',
|
||||
forceLabels: !!params.labels
|
||||
});
|
||||
|
||||
// Refreshing
|
||||
renderer.resize(w, h);
|
||||
this.refresh();
|
||||
|
||||
// Dropping camera and renderers before something nasty happens
|
||||
this.killRenderer(renderer);
|
||||
this.killCamera(camera);
|
||||
|
||||
// Retrieving svg
|
||||
var svg = container.querySelector('svg');
|
||||
svg.removeAttribute('style');
|
||||
svg.setAttribute('width', w + 'px');
|
||||
svg.setAttribute('height', h + 'px');
|
||||
svg.setAttribute('x', '0px');
|
||||
svg.setAttribute('y', '0px');
|
||||
// svg.setAttribute('viewBox', '0 0 1000 1000');
|
||||
|
||||
// Dropping labels
|
||||
if (!params.labels) {
|
||||
var labelGroup = svg.querySelector('[id="' + prefix + '-group-labels"]');
|
||||
svg.removeChild(labelGroup);
|
||||
}
|
||||
|
||||
// Dropping hovers
|
||||
var hoverGroup = svg.querySelector('[id="' + prefix + '-group-hovers"]');
|
||||
svg.removeChild(hoverGroup);
|
||||
|
||||
// Optims?
|
||||
params.classes = (params.classes !== false);
|
||||
if (!params.data || params.classes)
|
||||
optimize(svg, prefix, params);
|
||||
|
||||
// Retrieving svg string
|
||||
var svgString = svg.outerHTML;
|
||||
|
||||
// Paranoid cleanup
|
||||
container = null;
|
||||
|
||||
// Output string
|
||||
var output = '<?xml version="1.0" encoding="utf-8"?>\n';
|
||||
output += '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n';
|
||||
output += svgString;
|
||||
|
||||
if (params.download)
|
||||
download(output, params.filename || DEFAULTS.filename);
|
||||
|
||||
return output;
|
||||
};
|
||||
}).call(this);
|
|
@ -0,0 +1,28 @@
|
|||
module.exports = function(grunt) {
|
||||
|
||||
|
||||
// Setting grunt base as sigma's root directory
|
||||
grunt.file.setBase('../../');
|
||||
|
||||
// Registering needed files
|
||||
var files = ['supervisor.js', 'worker.js'].map(function(p) {
|
||||
return __dirname + '/' + p;
|
||||
});
|
||||
|
||||
// Project configuration:
|
||||
grunt.initConfig({
|
||||
forceAtlas2: {
|
||||
prod: {
|
||||
files: {
|
||||
'build/plugins/sigma.layout.forceAtlas2.min.js': files
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Loading tasks
|
||||
grunt.loadTasks(__dirname + '/tasks');
|
||||
|
||||
// By default, we will crush and then minify
|
||||
grunt.registerTask('default', ['forceAtlas2:prod']);
|
||||
};
|
|
@ -0,0 +1,79 @@
|
|||
sigma.layout.forceAtlas2
|
||||
========================
|
||||
|
||||
Algorithm by [Mathieu Jacomy](https://github.com/jacomyma).
|
||||
|
||||
Plugin by [Guillaume Plique](https://github.com/Yomguithereal).
|
||||
|
||||
---
|
||||
|
||||
This plugin implements [ForceAtlas2](http://www.plosone.org/article/info%3Adoi%2F10.1371%2Fjournal.pone.0098679), a force-directed layout algorithm.
|
||||
|
||||
For optimization purposes, the algorithm's computations are delegated to a web worker.
|
||||
|
||||
## Methods
|
||||
|
||||
**sigma.startForceAtlas2**
|
||||
|
||||
Starts or unpauses the layout. It is possible to pass a configuration if this is the first time you start the layout.
|
||||
|
||||
```js
|
||||
sigmaInstance.startForceAtlas2(config);
|
||||
```
|
||||
|
||||
**sigma.stopForceAtlas2**
|
||||
|
||||
Pauses the layout.
|
||||
|
||||
```js
|
||||
sigmaInstance.stopForceAtlas2();
|
||||
```
|
||||
|
||||
**sigma.configForceAtlas2**
|
||||
|
||||
Changes the layout's configuration.
|
||||
|
||||
```js
|
||||
sigmaInstance.configForceAtlas2(config);
|
||||
```
|
||||
|
||||
**sigma.killForceAtlas2**
|
||||
|
||||
Completely stops the layout and terminates the assiociated worker. You can still restart it later, but a new worker will have to initialize.
|
||||
|
||||
```js
|
||||
sigmaInstance.killForceAtlas2();
|
||||
```
|
||||
|
||||
**sigma.isForceAtlas2Running**
|
||||
|
||||
Returns whether ForceAtlas2 is running.
|
||||
|
||||
```js
|
||||
sigmaInstance.isForceAtlas2Running();
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
*Algorithm configuration*
|
||||
|
||||
* **linLogMode** *boolean* `false`: switch ForceAtlas' model from lin-lin to lin-log (tribute to Andreas Noack). Makes clusters more tight.
|
||||
* **outboundAttractionDistribution** *boolean* `false`
|
||||
* **adjustSizes** *boolean* `false`
|
||||
* **edgeWeightInfluence** *number* `0`: how much influence you give to the edges weight. 0 is "no influence" and 1 is "normal".
|
||||
* **scalingRatio** *number* `1`: how much repulsion you want. More makes a more sparse graph.
|
||||
* **strongGravityMode** *boolean* `false`
|
||||
* **gravity** *number* `1`: attracts nodes to the center. Prevents islands from drifting away.
|
||||
* **barnesHutOptimize** *boolean* `true`: should we use the algorithm's Barnes-Hut to improve repulsion's scalability (`O(n²)` to `O(nlog(n))`)? This is useful for large graph but harmful to small ones.
|
||||
* **barnesHutTheta** *number* `0.5`
|
||||
* **slowDown** *number* `1`
|
||||
* **startingIterations** *integer* `1`: number of iterations to be run before the first render.
|
||||
* **iterationsPerRender** *integer* `1`: number of iterations to be run before each render.
|
||||
|
||||
*Supervisor configuration*
|
||||
|
||||
* **worker** *boolean* `true`: should the layout use a web worker?
|
||||
* **workerUrl** *string* : path to the worker file if needed because your browser does not support blob workers.
|
||||
|
||||
## Notes
|
||||
1. The layout won't stop by itself, so if you want it to stop, you will have to trigger it explicitly.
|
|
@ -0,0 +1,340 @@
|
|||
;(function(undefined) {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined')
|
||||
throw 'sigma is not declared';
|
||||
|
||||
/**
|
||||
* Sigma ForceAtlas2.5 Supervisor
|
||||
* ===============================
|
||||
*
|
||||
* Author: Guillaume Plique (Yomguithereal)
|
||||
* Version: 0.1
|
||||
*/
|
||||
var _root = this;
|
||||
|
||||
/**
|
||||
* Feature detection
|
||||
* ------------------
|
||||
*/
|
||||
var webWorkers = 'Worker' in _root;
|
||||
|
||||
/**
|
||||
* Supervisor Object
|
||||
* ------------------
|
||||
*/
|
||||
function Supervisor(sigInst, options) {
|
||||
var _this = this,
|
||||
workerFn = sigInst.getForceAtlas2Worker &&
|
||||
sigInst.getForceAtlas2Worker();
|
||||
|
||||
options = options || {};
|
||||
|
||||
// _root URL Polyfill
|
||||
_root.URL = _root.URL || _root.webkitURL;
|
||||
|
||||
// Properties
|
||||
this.sigInst = sigInst;
|
||||
this.graph = this.sigInst.graph;
|
||||
this.ppn = 10;
|
||||
this.ppe = 3;
|
||||
this.config = {};
|
||||
this.shouldUseWorker =
|
||||
options.worker === false ? false : true && webWorkers;
|
||||
this.workerUrl = options.workerUrl;
|
||||
|
||||
// State
|
||||
this.started = false;
|
||||
this.running = false;
|
||||
|
||||
// Web worker or classic DOM events?
|
||||
if (this.shouldUseWorker) {
|
||||
if (!this.workerUrl) {
|
||||
var blob = this.makeBlob(workerFn);
|
||||
this.worker = new Worker(URL.createObjectURL(blob));
|
||||
}
|
||||
else {
|
||||
this.worker = new Worker(this.workerUrl);
|
||||
}
|
||||
|
||||
// Post Message Polyfill
|
||||
this.worker.postMessage =
|
||||
this.worker.webkitPostMessage || this.worker.postMessage;
|
||||
}
|
||||
else {
|
||||
|
||||
eval(workerFn);
|
||||
}
|
||||
|
||||
// Worker message receiver
|
||||
this.msgName = (this.worker) ? 'message' : 'newCoords';
|
||||
this.listener = function(e) {
|
||||
|
||||
// Retrieving data
|
||||
_this.nodesByteArray = new Float32Array(e.data.nodes);
|
||||
|
||||
// If ForceAtlas2 is running, we act accordingly
|
||||
if (_this.running) {
|
||||
|
||||
// Applying layout
|
||||
_this.applyLayoutChanges();
|
||||
|
||||
// Send data back to worker and loop
|
||||
_this.sendByteArrayToWorker();
|
||||
|
||||
// Rendering graph
|
||||
_this.sigInst.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
(this.worker || document).addEventListener(this.msgName, this.listener);
|
||||
|
||||
// Filling byteArrays
|
||||
this.graphToByteArrays();
|
||||
|
||||
// Binding on kill to properly terminate layout when parent is killed
|
||||
sigInst.bind('kill', function() {
|
||||
sigInst.killForceAtlas2();
|
||||
});
|
||||
}
|
||||
|
||||
Supervisor.prototype.makeBlob = function(workerFn) {
|
||||
var blob;
|
||||
|
||||
try {
|
||||
blob = new Blob([workerFn], {type: 'application/javascript'});
|
||||
}
|
||||
catch (e) {
|
||||
_root.BlobBuilder = _root.BlobBuilder ||
|
||||
_root.WebKitBlobBuilder ||
|
||||
_root.MozBlobBuilder;
|
||||
|
||||
blob = new BlobBuilder();
|
||||
blob.append(workerFn);
|
||||
blob = blob.getBlob();
|
||||
}
|
||||
|
||||
return blob;
|
||||
};
|
||||
|
||||
Supervisor.prototype.graphToByteArrays = function() {
|
||||
var nodes = this.graph.nodes(),
|
||||
edges = this.graph.edges(),
|
||||
nbytes = nodes.length * this.ppn,
|
||||
ebytes = edges.length * this.ppe,
|
||||
nIndex = {},
|
||||
i,
|
||||
j,
|
||||
l;
|
||||
|
||||
// Allocating Byte arrays with correct nb of bytes
|
||||
this.nodesByteArray = new Float32Array(nbytes);
|
||||
this.edgesByteArray = new Float32Array(ebytes);
|
||||
|
||||
// Iterate through nodes
|
||||
for (i = j = 0, l = nodes.length; i < l; i++) {
|
||||
|
||||
// Populating index
|
||||
nIndex[nodes[i].id] = j;
|
||||
|
||||
// Populating byte array
|
||||
this.nodesByteArray[j] = nodes[i].x;
|
||||
this.nodesByteArray[j + 1] = nodes[i].y;
|
||||
this.nodesByteArray[j + 2] = 0;
|
||||
this.nodesByteArray[j + 3] = 0;
|
||||
this.nodesByteArray[j + 4] = 0;
|
||||
this.nodesByteArray[j + 5] = 0;
|
||||
this.nodesByteArray[j + 6] = 1 + this.graph.degree(nodes[i].id);
|
||||
this.nodesByteArray[j + 7] = 1;
|
||||
this.nodesByteArray[j + 8] = nodes[i].size;
|
||||
this.nodesByteArray[j + 9] = 0;
|
||||
j += this.ppn;
|
||||
}
|
||||
|
||||
// Iterate through edges
|
||||
for (i = j = 0, l = edges.length; i < l; i++) {
|
||||
this.edgesByteArray[j] = nIndex[edges[i].source];
|
||||
this.edgesByteArray[j + 1] = nIndex[edges[i].target];
|
||||
this.edgesByteArray[j + 2] = edges[i].weight || 0;
|
||||
j += this.ppe;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: make a better send function
|
||||
Supervisor.prototype.applyLayoutChanges = function() {
|
||||
var nodes = this.graph.nodes(),
|
||||
j = 0,
|
||||
realIndex;
|
||||
|
||||
// Moving nodes
|
||||
for (var i = 0, l = this.nodesByteArray.length; i < l; i += this.ppn) {
|
||||
nodes[j].x = this.nodesByteArray[i];
|
||||
nodes[j].y = this.nodesByteArray[i + 1];
|
||||
j++;
|
||||
}
|
||||
};
|
||||
|
||||
Supervisor.prototype.sendByteArrayToWorker = function(action) {
|
||||
var content = {
|
||||
action: action || 'loop',
|
||||
nodes: this.nodesByteArray.buffer
|
||||
};
|
||||
|
||||
var buffers = [this.nodesByteArray.buffer];
|
||||
|
||||
if (action === 'start') {
|
||||
content.config = this.config || {};
|
||||
content.edges = this.edgesByteArray.buffer;
|
||||
buffers.push(this.edgesByteArray.buffer);
|
||||
}
|
||||
|
||||
if (this.shouldUseWorker)
|
||||
this.worker.postMessage(content, buffers);
|
||||
else
|
||||
_root.postMessage(content, '*');
|
||||
};
|
||||
|
||||
Supervisor.prototype.start = function() {
|
||||
if (this.running)
|
||||
return;
|
||||
|
||||
this.running = true;
|
||||
|
||||
// Do not refresh edgequadtree during layout:
|
||||
var k,
|
||||
c;
|
||||
for (k in this.sigInst.cameras) {
|
||||
c = this.sigInst.cameras[k];
|
||||
c.edgequadtree._enabled = false;
|
||||
}
|
||||
|
||||
if (!this.started) {
|
||||
|
||||
// Sending init message to worker
|
||||
this.sendByteArrayToWorker('start');
|
||||
this.started = true;
|
||||
}
|
||||
else {
|
||||
this.sendByteArrayToWorker();
|
||||
}
|
||||
};
|
||||
|
||||
Supervisor.prototype.stop = function() {
|
||||
if (!this.running)
|
||||
return;
|
||||
|
||||
// Allow to refresh edgequadtree:
|
||||
var k,
|
||||
c,
|
||||
bounds;
|
||||
for (k in this.sigInst.cameras) {
|
||||
c = this.sigInst.cameras[k];
|
||||
c.edgequadtree._enabled = true;
|
||||
|
||||
// Find graph boundaries:
|
||||
bounds = sigma.utils.getBoundaries(
|
||||
this.graph,
|
||||
c.readPrefix
|
||||
);
|
||||
|
||||
// Refresh edgequadtree:
|
||||
if (c.settings('drawEdges') && c.settings('enableEdgeHovering'))
|
||||
c.edgequadtree.index(this.sigInst.graph, {
|
||||
prefix: c.readPrefix,
|
||||
bounds: {
|
||||
x: bounds.minX,
|
||||
y: bounds.minY,
|
||||
width: bounds.maxX - bounds.minX,
|
||||
height: bounds.maxY - bounds.minY
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.running = false;
|
||||
};
|
||||
|
||||
Supervisor.prototype.killWorker = function() {
|
||||
if (this.worker) {
|
||||
this.worker.terminate();
|
||||
}
|
||||
else {
|
||||
_root.postMessage({action: 'kill'}, '*');
|
||||
document.removeEventListener(this.msgName, this.listener);
|
||||
}
|
||||
};
|
||||
|
||||
Supervisor.prototype.configure = function(config) {
|
||||
|
||||
// Setting configuration
|
||||
this.config = config;
|
||||
|
||||
if (!this.started)
|
||||
return;
|
||||
|
||||
var data = {action: 'config', config: this.config};
|
||||
|
||||
if (this.shouldUseWorker)
|
||||
this.worker.postMessage(data);
|
||||
else
|
||||
_root.postMessage(data, '*');
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface
|
||||
* ----------
|
||||
*/
|
||||
sigma.prototype.startForceAtlas2 = function(config) {
|
||||
|
||||
// Create supervisor if undefined
|
||||
if (!this.supervisor)
|
||||
this.supervisor = new Supervisor(this, config);
|
||||
|
||||
// Configuration provided?
|
||||
if (config)
|
||||
this.supervisor.configure(config);
|
||||
|
||||
// Start algorithm
|
||||
this.supervisor.start();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
sigma.prototype.stopForceAtlas2 = function() {
|
||||
if (!this.supervisor)
|
||||
return this;
|
||||
|
||||
// Pause algorithm
|
||||
this.supervisor.stop();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
sigma.prototype.killForceAtlas2 = function() {
|
||||
if (!this.supervisor)
|
||||
return this;
|
||||
|
||||
// Stop Algorithm
|
||||
this.supervisor.stop();
|
||||
|
||||
// Kill Worker
|
||||
this.supervisor.killWorker();
|
||||
|
||||
// Kill supervisor
|
||||
this.supervisor = null;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
sigma.prototype.configForceAtlas2 = function(config) {
|
||||
if (!this.supervisor)
|
||||
this.supervisor = new Supervisor(this, config);
|
||||
|
||||
this.supervisor.configure(config);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
sigma.prototype.isForceAtlas2Running = function(config) {
|
||||
return !!this.supervisor && this.supervisor.running;
|
||||
};
|
||||
}).call(this);
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* grunt-forceAtlas2
|
||||
*
|
||||
* This task crush and minify Force Atlas 2 code.
|
||||
*/
|
||||
var uglify = require('uglify-js');
|
||||
|
||||
// Shorteners
|
||||
function minify(string) {
|
||||
return uglify.minify(string, {fromString: true}).code;
|
||||
}
|
||||
|
||||
// Crushing function
|
||||
function crush(fnString) {
|
||||
var pattern,
|
||||
i,
|
||||
l;
|
||||
|
||||
var np = [
|
||||
'x',
|
||||
'y',
|
||||
'dx',
|
||||
'dy',
|
||||
'old_dx',
|
||||
'old_dy',
|
||||
'mass',
|
||||
'convergence',
|
||||
'size',
|
||||
'fixed'
|
||||
];
|
||||
|
||||
var ep = [
|
||||
'source',
|
||||
'target',
|
||||
'weight'
|
||||
];
|
||||
|
||||
var rp = [
|
||||
'node',
|
||||
'centerX',
|
||||
'centerY',
|
||||
'size',
|
||||
'nextSibling',
|
||||
'firstChild',
|
||||
'mass',
|
||||
'massCenterX',
|
||||
'massCenterY'
|
||||
];
|
||||
|
||||
// Replacing matrix accessors by incremented indexes
|
||||
for (i = 0, l = rp.length; i < l; i++) {
|
||||
pattern = new RegExp('rp\\(([^,]*), \'' + rp[i] + '\'\\)', 'g');
|
||||
fnString = fnString.replace(
|
||||
pattern,
|
||||
(i === 0) ? '$1' : '$1 + ' + i
|
||||
);
|
||||
}
|
||||
|
||||
for (i = 0, l = np.length; i < l; i++) {
|
||||
pattern = new RegExp('np\\(([^,]*), \'' + np[i] + '\'\\)', 'g');
|
||||
fnString = fnString.replace(
|
||||
pattern,
|
||||
(i === 0) ? '$1' : '$1 + ' + i
|
||||
);
|
||||
}
|
||||
|
||||
for (i = 0, l = ep.length; i < l; i++) {
|
||||
pattern = new RegExp('ep\\(([^,]*), \'' + ep[i] + '\'\\)', 'g');
|
||||
fnString = fnString.replace(
|
||||
pattern,
|
||||
(i === 0) ? '$1' : '$1 + ' + i
|
||||
);
|
||||
}
|
||||
|
||||
return fnString;
|
||||
}
|
||||
|
||||
// Cleaning function
|
||||
function clean(string) {
|
||||
return string.replace(
|
||||
/function crush\(fnString\)/,
|
||||
'var crush = null; function no_crush(fnString)'
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = function(grunt) {
|
||||
|
||||
// Force atlas grunt multitask
|
||||
function multitask() {
|
||||
|
||||
// Merge task-specific and/or target-specific options with these defaults.
|
||||
var options = this.options({});
|
||||
|
||||
// Iterate over all specified file groups.
|
||||
this.files.forEach(function(f) {
|
||||
// Concat specified files.
|
||||
var src = f.src.filter(function(filepath) {
|
||||
// Warn on and remove invalid source files (if nonull was set).
|
||||
if (!grunt.file.exists(filepath)) {
|
||||
grunt.log.warn('Source file "' + filepath + '" not found.');
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}).map(function(filepath) {
|
||||
// Read file source.
|
||||
return grunt.file.read(filepath);
|
||||
}).join('\n');
|
||||
|
||||
// Crushing, cleaning and minifying
|
||||
src = minify(clean(crush(src)));
|
||||
|
||||
// Write the destination file.
|
||||
grunt.file.write(f.dest, src);
|
||||
|
||||
// Print a success message.
|
||||
grunt.log.writeln('File "' + f.dest + '" created.');
|
||||
});
|
||||
}
|
||||
|
||||
// Registering the task
|
||||
grunt.registerMultiTask(
|
||||
'forceAtlas2',
|
||||
'A grunt task to crush and minify ForceAtlas2.',
|
||||
multitask
|
||||
);
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,87 @@
|
|||
sigma.layout.noverlap
|
||||
========================
|
||||
|
||||
Plugin developed by [Andrew Pitts](https://github.com/apitts) and published under the [MIT](LICENSE) license. Original algorithm by [Mathieu Jacomy](https://github.com/jacomyma) and ported to sigma.js with permission.
|
||||
|
||||
---
|
||||
|
||||
This plugin runs an algorithm which distributes nodes in the network, ensuring that they do not overlap and providing a margin where specified.
|
||||
|
||||
## Methods
|
||||
|
||||
**configure**
|
||||
|
||||
Changes the layout's configuration.
|
||||
|
||||
```js
|
||||
var listener = s.configNoverlap(config);
|
||||
```
|
||||
|
||||
**start**
|
||||
|
||||
Starts the layout. It is possible to pass a configuration if this is the first time you start the layout.
|
||||
|
||||
```js
|
||||
s.startNoverlap();
|
||||
```
|
||||
|
||||
**isRunning**
|
||||
|
||||
Returns whether the layout is running.
|
||||
|
||||
```js
|
||||
s.isNoverlapRunning();
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
* **nodes**: *array*: the subset of nodes to apply the layout.
|
||||
|
||||
*Algorithm configuration*
|
||||
|
||||
* **nodeMargin**: *number* `5.0`: The additional minimum space to apply around each and every node.
|
||||
* **scaleNodes**: *number* `1.2`: A multiplier to apply to nodes such that larger nodes will have more space around them if this multiplier is greater than zero.
|
||||
* **gridSize**: *integer* `20`: The number of rows and columns to use when dividing the nodes up into cells which the algorithm is applied to. Use more rows and columns for larger graphs for a more efficient algorithm.
|
||||
* **permittedExpansion** *number* `1.1`: At every step, this is the maximum ratio to apply to the bounding box, i.e. the maximum by which the network is permitted to expand.
|
||||
* **rendererIndex** *integer* `0`: The index of the renderer to use to compute overlap and collisions of the nodes.
|
||||
* **speed** *number* `2`: A larger value increases the speed with which the algorithm will convergence at the cost of precision.
|
||||
* **maxIterations** *number* `500`: The maximum number of iterations to run the algorithm for before stopping it.
|
||||
|
||||
*Easing configuration*
|
||||
|
||||
* **easing** *string*: if specified, ease the transition between nodes positions if background is `true`. The duration is specified by the Sigma settings `animationsTime`. See [sigma.utils.easing](../../src/utils/sigma.utils.js#L723) for available values.
|
||||
* **duration** *number*: duration of the transition for the easing method. Default value is Sigma setting `animationsTime`.
|
||||
|
||||
## Events
|
||||
|
||||
The plugin dispatches the following events:
|
||||
|
||||
- `start`: on layout start.
|
||||
- `interpolate`: at the beginning of the layout animation if an *easing* function is specified and the layout is ran on background.
|
||||
- `stop`: on layout stop, will be dispatched after `interpolate`.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
|
||||
s = new sigma({
|
||||
graph: g,
|
||||
container: 'graph-container'
|
||||
});
|
||||
|
||||
var config = {
|
||||
nodeMargin: 3.0,
|
||||
scaleNodes: 1.3
|
||||
};
|
||||
|
||||
// Configure the algorithm
|
||||
var listener = s.configNoverlap(config);
|
||||
|
||||
// Bind all events:
|
||||
listener.bind('start stop interpolate', function(event) {
|
||||
console.log(event.type);
|
||||
});
|
||||
|
||||
// Start the algorithm:
|
||||
s.startNoverlap();
|
||||
```
|
|
@ -0,0 +1,408 @@
|
|||
;(function(undefined) {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined')
|
||||
throw new Error('sigma is not declared');
|
||||
|
||||
// Initialize package:
|
||||
sigma.utils.pkg('sigma.layout.noverlap');
|
||||
|
||||
/**
|
||||
* Noverlap Layout
|
||||
* ===============================
|
||||
*
|
||||
* Author: @apitts / Andrew Pitts
|
||||
* Algorithm: @jacomyma / Mathieu Jacomy (originally contributed to Gephi and ported to sigma.js under the MIT license by @andpitts with permission)
|
||||
* Acknowledgement: @sheyman / Sébastien Heymann (some inspiration has been taken from other MIT licensed layout algorithms authored by @sheyman)
|
||||
* Version: 0.1
|
||||
*/
|
||||
|
||||
var settings = {
|
||||
speed: 3,
|
||||
scaleNodes: 1.2,
|
||||
nodeMargin: 5.0,
|
||||
gridSize: 20,
|
||||
permittedExpansion: 1.1,
|
||||
rendererIndex: 0,
|
||||
maxIterations: 500
|
||||
};
|
||||
|
||||
var _instance = {};
|
||||
|
||||
/**
|
||||
* Event emitter Object
|
||||
* ------------------
|
||||
*/
|
||||
var _eventEmitter = {};
|
||||
|
||||
/**
|
||||
* Noverlap Object
|
||||
* ------------------
|
||||
*/
|
||||
function Noverlap() {
|
||||
var self = this;
|
||||
|
||||
this.init = function (sigInst, options) {
|
||||
options = options || {};
|
||||
|
||||
// Properties
|
||||
this.sigInst = sigInst;
|
||||
this.config = sigma.utils.extend(options, settings);
|
||||
this.easing = options.easing;
|
||||
this.duration = options.duration;
|
||||
|
||||
if (options.nodes) {
|
||||
this.nodes = options.nodes;
|
||||
delete options.nodes;
|
||||
}
|
||||
|
||||
if (!sigma.plugins || typeof sigma.plugins.animate === 'undefined') {
|
||||
throw new Error('sigma.plugins.animate is not declared');
|
||||
}
|
||||
|
||||
// State
|
||||
this.running = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Single layout iteration.
|
||||
*/
|
||||
this.atomicGo = function () {
|
||||
if (!this.running || this.iterCount < 1) return false;
|
||||
|
||||
var nodes = this.nodes || this.sigInst.graph.nodes(),
|
||||
nodesCount = nodes.length,
|
||||
i,
|
||||
n,
|
||||
n1,
|
||||
n2,
|
||||
xmin = Infinity,
|
||||
xmax = -Infinity,
|
||||
ymin = Infinity,
|
||||
ymax = -Infinity,
|
||||
xwidth,
|
||||
yheight,
|
||||
xcenter,
|
||||
ycenter,
|
||||
grid,
|
||||
row,
|
||||
col,
|
||||
minXBox,
|
||||
maxXBox,
|
||||
minYBox,
|
||||
maxYBox,
|
||||
adjacentNodes,
|
||||
subRow,
|
||||
subCol,
|
||||
nxmin,
|
||||
nxmax,
|
||||
nymin,
|
||||
nymax;
|
||||
|
||||
this.iterCount--;
|
||||
this.running = false;
|
||||
|
||||
for (i=0; i < nodesCount; i++) {
|
||||
n = nodes[i];
|
||||
n.dn.dx = 0;
|
||||
n.dn.dy = 0;
|
||||
|
||||
//Find the min and max for both x and y across all nodes
|
||||
xmin = Math.min(xmin, n.dn_x - (n.dn_size*self.config.scaleNodes + self.config.nodeMargin) );
|
||||
xmax = Math.max(xmax, n.dn_x + (n.dn_size*self.config.scaleNodes + self.config.nodeMargin) );
|
||||
ymin = Math.min(ymin, n.dn_y - (n.dn_size*self.config.scaleNodes + self.config.nodeMargin) );
|
||||
ymax = Math.max(ymax, n.dn_y + (n.dn_size*self.config.scaleNodes + self.config.nodeMargin) );
|
||||
|
||||
}
|
||||
|
||||
xwidth = xmax - xmin;
|
||||
yheight = ymax - ymin;
|
||||
xcenter = (xmin + xmax) / 2;
|
||||
ycenter = (ymin + ymax) / 2;
|
||||
xmin = xcenter - self.config.permittedExpansion*xwidth / 2;
|
||||
xmax = xcenter + self.config.permittedExpansion*xwidth / 2;
|
||||
ymin = ycenter - self.config.permittedExpansion*yheight / 2;
|
||||
ymax = ycenter + self.config.permittedExpansion*yheight / 2;
|
||||
|
||||
grid = {}; //An object of objects where grid[row][col] is an array of node ids representing nodes that fall in that grid. Nodes can fall in more than one grid
|
||||
|
||||
for(row = 0; row < self.config.gridSize; row++) {
|
||||
grid[row] = {};
|
||||
for(col = 0; col < self.config.gridSize; col++) {
|
||||
grid[row][col] = [];
|
||||
}
|
||||
}
|
||||
|
||||
//Place nodes in grid
|
||||
for (i=0; i < nodesCount; i++) {
|
||||
n = nodes[i];
|
||||
|
||||
nxmin = n.dn_x - (n.dn_size*self.config.scaleNodes + self.config.nodeMargin);
|
||||
nxmax = n.dn_x + (n.dn_size*self.config.scaleNodes + self.config.nodeMargin);
|
||||
nymin = n.dn_y - (n.dn_size*self.config.scaleNodes + self.config.nodeMargin);
|
||||
nymax = n.dn_y + (n.dn_size*self.config.scaleNodes + self.config.nodeMargin);
|
||||
|
||||
minXBox = Math.floor(self.config.gridSize* (nxmin - xmin) / (xmax - xmin) );
|
||||
maxXBox = Math.floor(self.config.gridSize* (nxmax - xmin) / (xmax - xmin) );
|
||||
minYBox = Math.floor(self.config.gridSize* (nymin - ymin) / (ymax - ymin) );
|
||||
maxYBox = Math.floor(self.config.gridSize* (nymax - ymin) / (ymax - ymin) );
|
||||
for(col = minXBox; col <= maxXBox; col++) {
|
||||
for(row = minYBox; row <= maxYBox; row++) {
|
||||
grid[row][col].push(n.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
adjacentNodes = {}; //An object that stores the node ids of adjacent nodes (either in same grid box or adjacent grid box) for all nodes
|
||||
|
||||
for(row = 0; row < self.config.gridSize; row++) {
|
||||
for(col = 0; col < self.config.gridSize; col++) {
|
||||
grid[row][col].forEach(function(nodeId) {
|
||||
if(!adjacentNodes[nodeId]) {
|
||||
adjacentNodes[nodeId] = [];
|
||||
}
|
||||
for(subRow = Math.max(0, row - 1); subRow <= Math.min(row + 1, self.config.gridSize - 1); subRow++) {
|
||||
for(subCol = Math.max(0, col - 1); subCol <= Math.min(col + 1, self.config.gridSize - 1); subCol++) {
|
||||
grid[subRow][subCol].forEach(function(subNodeId) {
|
||||
if(subNodeId !== nodeId && adjacentNodes[nodeId].indexOf(subNodeId) === -1) {
|
||||
adjacentNodes[nodeId].push(subNodeId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//If two nodes overlap then repulse them
|
||||
for (i=0; i < nodesCount; i++) {
|
||||
n1 = nodes[i];
|
||||
adjacentNodes[n1.id].forEach(function(nodeId) {
|
||||
var n2 = self.sigInst.graph.nodes(nodeId);
|
||||
var xDist = n2.dn_x - n1.dn_x;
|
||||
var yDist = n2.dn_y - n1.dn_y;
|
||||
var dist = Math.sqrt(xDist*xDist + yDist*yDist);
|
||||
var collision = (dist < ((n1.dn_size*self.config.scaleNodes + self.config.nodeMargin) + (n2.dn_size*self.config.scaleNodes + self.config.nodeMargin)));
|
||||
if(collision) {
|
||||
self.running = true;
|
||||
if(dist > 0) {
|
||||
n2.dn.dx += xDist / dist * (1 + n1.dn_size);
|
||||
n2.dn.dy += yDist / dist * (1 + n1.dn_size);
|
||||
} else {
|
||||
n2.dn.dx += xwidth * 0.01 * (0.5 - Math.random());
|
||||
n2.dn.dy += yheight * 0.01 * (0.5 - Math.random());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (i=0; i < nodesCount; i++) {
|
||||
n = nodes[i];
|
||||
if(!n.fixed) {
|
||||
n.dn_x = n.dn_x + n.dn.dx * 0.1 * self.config.speed;
|
||||
n.dn_y = n.dn_y + n.dn.dy * 0.1 * self.config.speed;
|
||||
}
|
||||
}
|
||||
|
||||
if(this.running && this.iterCount < 1) {
|
||||
this.running = false;
|
||||
}
|
||||
|
||||
return this.running;
|
||||
};
|
||||
|
||||
this.go = function () {
|
||||
this.iterCount = this.config.maxIterations;
|
||||
|
||||
while (this.running) {
|
||||
this.atomicGo();
|
||||
};
|
||||
|
||||
this.stop();
|
||||
};
|
||||
|
||||
this.start = function() {
|
||||
if (this.running) return;
|
||||
|
||||
var nodes = this.sigInst.graph.nodes();
|
||||
|
||||
var prefix = this.sigInst.renderers[self.config.rendererIndex].options.prefix;
|
||||
|
||||
this.running = true;
|
||||
|
||||
// Init nodes
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
nodes[i].dn_x = nodes[i][prefix + 'x'];
|
||||
nodes[i].dn_y = nodes[i][prefix + 'y'];
|
||||
nodes[i].dn_size = nodes[i][prefix + 'size'];
|
||||
nodes[i].dn = {
|
||||
dx: 0,
|
||||
dy: 0
|
||||
};
|
||||
}
|
||||
_eventEmitter[self.sigInst.id].dispatchEvent('start');
|
||||
this.go();
|
||||
};
|
||||
|
||||
this.stop = function() {
|
||||
var nodes = this.sigInst.graph.nodes();
|
||||
|
||||
this.running = false;
|
||||
|
||||
if (this.easing) {
|
||||
_eventEmitter[self.sigInst.id].dispatchEvent('interpolate');
|
||||
sigma.plugins.animate(
|
||||
self.sigInst,
|
||||
{
|
||||
x: 'dn_x',
|
||||
y: 'dn_y'
|
||||
},
|
||||
{
|
||||
easing: self.easing,
|
||||
onComplete: function() {
|
||||
self.sigInst.refresh();
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
nodes[i].dn = null;
|
||||
nodes[i].dn_x = null;
|
||||
nodes[i].dn_y = null;
|
||||
}
|
||||
_eventEmitter[self.sigInst.id].dispatchEvent('stop');
|
||||
},
|
||||
duration: self.duration
|
||||
}
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Apply changes
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
nodes[i].x = nodes[i].dn_x;
|
||||
nodes[i].y = nodes[i].dn_y;
|
||||
}
|
||||
|
||||
this.sigInst.refresh();
|
||||
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
nodes[i].dn = null;
|
||||
nodes[i].dn_x = null;
|
||||
nodes[i].dn_y = null;
|
||||
}
|
||||
_eventEmitter[self.sigInst.id].dispatchEvent('stop');
|
||||
}
|
||||
};
|
||||
|
||||
this.kill = function() {
|
||||
this.sigInst = null;
|
||||
this.config = null;
|
||||
this.easing = null;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface
|
||||
* ----------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Configure the layout algorithm.
|
||||
|
||||
* Recognized options:
|
||||
* **********************
|
||||
* Here is the exhaustive list of every accepted parameter in the settings
|
||||
* object:
|
||||
*
|
||||
* {?number} speed A larger value increases the convergence speed at the cost of precision
|
||||
* {?number} scaleNodes The ratio to scale nodes by - a larger ratio will lead to more space around larger nodes
|
||||
* {?number} nodeMargin A fixed margin to apply around nodes regardless of size
|
||||
* {?number} maxIterations The maximum number of iterations to perform before the layout completes.
|
||||
* {?integer} gridSize The number of rows and columns to use when partioning nodes into a grid for efficient computation
|
||||
* {?number} permittedExpansion A permitted expansion factor to the overall size of the network applied at each iteration
|
||||
* {?integer} rendererIndex The index of the renderer to use for node co-ordinates. Defaults to zero.
|
||||
* {?(function|string)} easing Either the name of an easing in the sigma.utils.easings package or a function. If not specified, the
|
||||
* quadraticInOut easing from this package will be used instead.
|
||||
* {?number} duration The duration of the animation. If not specified, the "animationsTime" setting value of the sigma instance will be used instead.
|
||||
*
|
||||
*
|
||||
* @param {object} config The optional configuration object.
|
||||
*
|
||||
* @return {sigma.classes.dispatcher} Returns an event emitter.
|
||||
*/
|
||||
sigma.prototype.configNoverlap = function(config) {
|
||||
|
||||
var sigInst = this;
|
||||
|
||||
if (!config) throw new Error('Missing argument: "config"');
|
||||
|
||||
// Create instance if undefined
|
||||
if (!_instance[sigInst.id]) {
|
||||
_instance[sigInst.id] = new Noverlap();
|
||||
|
||||
_eventEmitter[sigInst.id] = {};
|
||||
sigma.classes.dispatcher.extend(_eventEmitter[sigInst.id]);
|
||||
|
||||
// Binding on kill to clear the references
|
||||
sigInst.bind('kill', function() {
|
||||
_instance[sigInst.id].kill();
|
||||
_instance[sigInst.id] = null;
|
||||
_eventEmitter[sigInst.id] = null;
|
||||
});
|
||||
}
|
||||
|
||||
_instance[sigInst.id].init(sigInst, config);
|
||||
|
||||
return _eventEmitter[sigInst.id];
|
||||
};
|
||||
|
||||
/**
|
||||
* Start the layout algorithm. It will use the existing configuration if no
|
||||
* new configuration is passed.
|
||||
|
||||
* Recognized options:
|
||||
* **********************
|
||||
* Here is the exhaustive list of every accepted parameter in the settings
|
||||
* object
|
||||
*
|
||||
* {?number} speed A larger value increases the convergence speed at the cost of precision
|
||||
* {?number} scaleNodes The ratio to scale nodes by - a larger ratio will lead to more space around larger nodes
|
||||
* {?number} nodeMargin A fixed margin to apply around nodes regardless of size
|
||||
* {?number} maxIterations The maximum number of iterations to perform before the layout completes.
|
||||
* {?integer} gridSize The number of rows and columns to use when partioning nodes into a grid for efficient computation
|
||||
* {?number} permittedExpansion A permitted expansion factor to the overall size of the network applied at each iteration
|
||||
* {?integer} rendererIndex The index of the renderer to use for node co-ordinates. Defaults to zero.
|
||||
* {?(function|string)} easing Either the name of an easing in the sigma.utils.easings package or a function. If not specified, the
|
||||
* quadraticInOut easing from this package will be used instead.
|
||||
* {?number} duration The duration of the animation. If not specified, the "animationsTime" setting value of the sigma instance will be used instead.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param {object} config The optional configuration object.
|
||||
*
|
||||
* @return {sigma.classes.dispatcher} Returns an event emitter.
|
||||
*/
|
||||
|
||||
sigma.prototype.startNoverlap = function(config) {
|
||||
|
||||
var sigInst = this;
|
||||
|
||||
if (config) {
|
||||
this.configNoverlap(sigInst, config);
|
||||
}
|
||||
|
||||
_instance[sigInst.id].start();
|
||||
|
||||
return _eventEmitter[sigInst.id];
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the layout has started and is not completed.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
sigma.prototype.isNoverlapRunning = function() {
|
||||
|
||||
var sigInst = this;
|
||||
|
||||
return !!_instance[sigInst.id] && _instance[sigInst.id].running;
|
||||
};
|
||||
|
||||
}).call(this);
|
|
@ -0,0 +1,553 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
Preamble
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
TERMS AND CONDITIONS
|
||||
0. Definitions.
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
1. Source Code.
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
2. Basic Permissions.
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
4. Conveying Verbatim Copies.
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
5. Conveying Modified Source Versions.
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
6. Conveying Non-Source Forms.
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
7. Additional Terms.
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
8. Termination.
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
11. Patents.
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
12. No Surrender of Others' Freedom.
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
13. Use with the GNU Affero General Public License.
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
14. Revised Versions of this License.
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
15. Disclaimer of Warranty.
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
16. Limitation of Liability.
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
END OF TERMS AND CONDITIONS
|
||||
How to Apply These Terms to Your New Programs
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
{one line to give the program's name and a brief idea of what it does.}
|
||||
Copyright (C) {year} {name of author}
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
{project} Copyright (C) {year} {fullname}
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
@ -0,0 +1,58 @@
|
|||
sigma.neo4j.cypher
|
||||
====================
|
||||
|
||||
Plugin developed by [Benoît Simard](https://github.com/sim51).
|
||||
|
||||
---
|
||||
|
||||
This plugin provides a simple function, `sigma.neo4j.cypher()`, that will run a cypher query on a neo4j instance, parse the response, eventually instantiate sigma and fill the graph with the `graph.read()` method.
|
||||
|
||||
Nodes are created with the following structure :
|
||||
* id -> Neo4j node id
|
||||
* label -> Neo4j node id
|
||||
* neo4j_labels -> Labels of Neo4j node
|
||||
* neo4j_data -> All the properties of the neo4j node
|
||||
|
||||
Edges are created with the following structure :
|
||||
* id -> Neo4j edge id
|
||||
* label -> Neo4j edge type
|
||||
* neo4j_type -> Neo4j edge type
|
||||
* neo4j_data -> All the properties of Neo4j relationship
|
||||
|
||||
The most basic way to use this helper is to call it with a neo4j server url and a cypher query. It will then instantiate sigma, but after having added the graph into the config object.
|
||||
|
||||
For neo4j < 2.2
|
||||
````javascript
|
||||
sigma.neo4j.cypher(
|
||||
'http://localhost:7474',
|
||||
'MATCH (n) OPTIONAL MATCH (n)-[r]->(m) RETURN n,r,m LIMIT 100',
|
||||
{ container: 'myContainer' }
|
||||
);
|
||||
````
|
||||
|
||||
For neo4j >= 2.2, you must pass a neo4j user with its password. So instead of the neo4j url, you have to pass a neo4j server object like this :
|
||||
````javascript
|
||||
sigma.neo4j.cypher(
|
||||
{ url: 'http://localhost:7474', user:'neo4j', password:'admin' },
|
||||
'MATCH (n) OPTIONAL MATCH (n)-[r]->(m) RETURN n,r,m LIMIT 100',
|
||||
{ container: 'myContainer' }
|
||||
);
|
||||
````
|
||||
|
||||
It is also possible to update an existing instance's graph instead.
|
||||
|
||||
````javascript
|
||||
sigma.neo4j.cypher(
|
||||
{ url: 'http://localhost:7474', user:'neo4j', password:'admin' },
|
||||
'MATCH (n) OPTIONAL MATCH (n)-[r]->(m) RETURN n,r,m LIMIT 100',
|
||||
myExistingInstance,
|
||||
function() {
|
||||
myExistingInstance.refresh();
|
||||
}
|
||||
);
|
||||
````
|
||||
|
||||
There is two additional functions provided by the plugin :
|
||||
|
||||
* ```sigma.neo4j.getTypes({ url: 'http://localhost:7474', user:'neo4j', password:'admin' }, callback)``` : Return all relationship type of the database
|
||||
* ```sigma.neo4j.getLabels({ url: 'http://localhost:7474', user:'neo4j', password:'admin' }, callback)``` : Return all node label of the database
|
|
@ -0,0 +1,218 @@
|
|||
;(function (undefined) {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined')
|
||||
throw 'sigma is not declared';
|
||||
|
||||
// Declare neo4j package
|
||||
sigma.utils.pkg("sigma.neo4j");
|
||||
|
||||
// Initialize package:
|
||||
sigma.utils.pkg('sigma.utils');
|
||||
|
||||
|
||||
/**
|
||||
* This function is an helper for the neo4j communication.
|
||||
*
|
||||
* @param {string|object} neo4j The URL of neo4j server or a neo4j server object.
|
||||
* @param {string} endpoint Endpoint of the neo4j server
|
||||
* @param {string} method The calling method for the endpoint : 'GET' or 'POST'
|
||||
* @param {object|string} data Data that will be send to the server
|
||||
* @param {function} callback The callback function
|
||||
*/
|
||||
sigma.neo4j.send = function(neo4j, endpoint, method, data, callback) {
|
||||
var xhr = sigma.utils.xhr(),
|
||||
url, user, password;
|
||||
|
||||
// if neo4j arg is not an object
|
||||
url = neo4j;
|
||||
if(typeof neo4j === 'object') {
|
||||
url = neo4j.url;
|
||||
user = neo4j.user;
|
||||
password = neo4j.password;
|
||||
}
|
||||
|
||||
if (!xhr)
|
||||
throw 'XMLHttpRequest not supported, cannot load the file.';
|
||||
|
||||
// Construct the endpoint url
|
||||
url += endpoint;
|
||||
|
||||
xhr.open(method, url, true);
|
||||
if( user && password) {
|
||||
xhr.setRequestHeader('Authorization', 'Basic ' + btoa(user + ':' + password));
|
||||
}
|
||||
xhr.setRequestHeader('Accept', 'application/json');
|
||||
xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8');
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4) {
|
||||
// Call the callback if specified:
|
||||
callback(JSON.parse(xhr.responseText));
|
||||
}
|
||||
};
|
||||
xhr.send(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* This function parse a neo4j cypher query result, and transform it into
|
||||
* a sigma graph object.
|
||||
*
|
||||
* @param {object} result The server response of a cypher query.
|
||||
*
|
||||
* @return A graph object
|
||||
*/
|
||||
sigma.neo4j.cypher_parse = function(result) {
|
||||
var graph = { nodes: [], edges: [] },
|
||||
nodesMap = {},
|
||||
edgesMap = {},
|
||||
key;
|
||||
|
||||
// Iteration on all result data
|
||||
result.results[0].data.forEach(function (data) {
|
||||
|
||||
// iteration on graph for all node
|
||||
data.graph.nodes.forEach(function (node) {
|
||||
|
||||
var sigmaNode = {
|
||||
id : node.id,
|
||||
label : node.id,
|
||||
x : Math.random(),
|
||||
y : Math.random(),
|
||||
size : 1,
|
||||
color : '#000000',
|
||||
neo4j_labels : node.labels,
|
||||
neo4j_data : node.properties
|
||||
};
|
||||
|
||||
if (sigmaNode.id in nodesMap) {
|
||||
// do nothing
|
||||
} else {
|
||||
nodesMap[sigmaNode.id] = sigmaNode;
|
||||
}
|
||||
});
|
||||
|
||||
// iteration on graph for all node
|
||||
data.graph.relationships.forEach(function (edge) {
|
||||
var sigmaEdge = {
|
||||
id : edge.id,
|
||||
label : edge.type,
|
||||
source : edge.startNode,
|
||||
target : edge.endNode,
|
||||
color : '#7D7C8E',
|
||||
neo4j_type : edge.type,
|
||||
neo4j_data : edge.properties
|
||||
};
|
||||
|
||||
if (sigmaEdge.id in edgesMap) {
|
||||
// do nothing
|
||||
} else {
|
||||
edgesMap[sigmaEdge.id] = sigmaEdge;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// construct sigma nodes
|
||||
for (key in nodesMap) {
|
||||
graph.nodes.push(nodesMap[key]);
|
||||
}
|
||||
// construct sigma nodes
|
||||
for (key in edgesMap) {
|
||||
graph.edges.push(edgesMap[key]);
|
||||
}
|
||||
|
||||
return graph;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This function execute a cypher and create a new sigma instance or
|
||||
* updates the graph of a given instance. It is possible to give a callback
|
||||
* that will be executed at the end of the process.
|
||||
*
|
||||
* @param {object|string} neo4j The URL of neo4j server or a neo4j server object.
|
||||
* @param {string} cypher The cypher query
|
||||
* @param {?object|?sigma} sig A sigma configuration object or a sigma instance.
|
||||
* @param {?function} callback Eventually a callback to execute after
|
||||
* having parsed the file. It will be called
|
||||
* with the related sigma instance as
|
||||
* parameter.
|
||||
*/
|
||||
sigma.neo4j.cypher = function (neo4j, cypher, sig, callback) {
|
||||
var endpoint = '/db/data/transaction/commit',
|
||||
data, cypherCallback;
|
||||
|
||||
// Data that will be send to the server
|
||||
data = JSON.stringify({
|
||||
"statements": [
|
||||
{
|
||||
"statement": cypher,
|
||||
"resultDataContents": ["graph"],
|
||||
"includeStats": false
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// Callback method after server response
|
||||
cypherCallback = function (callback) {
|
||||
|
||||
return function (response) {
|
||||
|
||||
var graph = { nodes: [], edges: [] };
|
||||
|
||||
graph = sigma.neo4j.cypher_parse(response);
|
||||
|
||||
// Update the instance's graph:
|
||||
if (sig instanceof sigma) {
|
||||
sig.graph.clear();
|
||||
sig.graph.read(graph);
|
||||
|
||||
// ...or instantiate sigma if needed:
|
||||
} else if (typeof sig === 'object') {
|
||||
sig = new sigma(sig);
|
||||
sig.graph.read(graph);
|
||||
sig.refresh();
|
||||
|
||||
// ...or it's finally the callback:
|
||||
} else if (typeof sig === 'function') {
|
||||
callback = sig;
|
||||
sig = null;
|
||||
}
|
||||
|
||||
// Call the callback if specified:
|
||||
if (callback)
|
||||
callback(sig || graph);
|
||||
};
|
||||
};
|
||||
|
||||
// Let's call neo4j
|
||||
sigma.neo4j.send(neo4j, endpoint, 'POST', data, cypherCallback(callback));
|
||||
};
|
||||
|
||||
/**
|
||||
* This function call neo4j to get all labels of the graph.
|
||||
*
|
||||
* @param {string} neo4j The URL of neo4j server or an object with the url, user & password.
|
||||
* @param {function} callback The callback function
|
||||
*
|
||||
* @return An array of label
|
||||
*/
|
||||
sigma.neo4j.getLabels = function(neo4j, callback) {
|
||||
sigma.neo4j.send(neo4j, '/db/data/labels', 'GET', null, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* This function parse a neo4j cypher query result.
|
||||
*
|
||||
* @param {string} neo4j The URL of neo4j server or an object with the url, user & password.
|
||||
* @param {function} callback The callback function
|
||||
*
|
||||
* @return An array of relationship type
|
||||
*/
|
||||
sigma.neo4j.getTypes = function(neo4j, callback) {
|
||||
sigma.neo4j.send(neo4j, '/db/data/relationship/types', 'GET', null, callback);
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
sigma.parsers.gexf
|
||||
==================
|
||||
|
||||
Plugin developed by [Alexis Jacomy](https://github.com/jacomyal), on top of [gexf-parser](https://github.com/Yomguithereal/gexf-parser), developed by [Guillaume Plique](https://github.com/Yomguithereal).
|
||||
|
||||
---
|
||||
|
||||
This plugin provides a single function, `sigma.parsers.gexf()`, that will load a GEXF encoded file, parse it, and instantiate sigma.
|
||||
|
||||
The most basic way to use this helper is to call it with a path and a sigma configuration object. It will then instantiate sigma, but after having added the graph into the config object.
|
||||
|
||||
````javascript
|
||||
sigma.parsers.gexf(
|
||||
'myGraph.gexf',
|
||||
{ container: 'myContainer' }
|
||||
);
|
||||
````
|
||||
|
||||
It is also possible to update an existing instance's graph instead.
|
||||
|
||||
````javascript
|
||||
sigma.parsers.gexf(
|
||||
'myGraph.gexf',
|
||||
myExistingInstance,
|
||||
function() {
|
||||
myExistingInstance.refresh();
|
||||
}
|
||||
);
|
||||
````
|
|
@ -0,0 +1,551 @@
|
|||
;(function(undefined) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* GEXF Library
|
||||
* =============
|
||||
*
|
||||
* Author: PLIQUE Guillaume (Yomguithereal)
|
||||
* URL: https://github.com/Yomguithereal/gexf-parser
|
||||
* Version: 0.1.1
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helper Namespace
|
||||
* -----------------
|
||||
*
|
||||
* A useful batch of function dealing with DOM operations and types.
|
||||
*/
|
||||
var _helpers = {
|
||||
getModelTags: function(xml) {
|
||||
var attributesTags = xml.getElementsByTagName('attributes'),
|
||||
modelTags = {},
|
||||
l = attributesTags.length,
|
||||
i;
|
||||
|
||||
for (i = 0; i < l; i++)
|
||||
modelTags[attributesTags[i].getAttribute('class')] =
|
||||
attributesTags[i].childNodes;
|
||||
|
||||
return modelTags;
|
||||
},
|
||||
nodeListToArray: function(nodeList) {
|
||||
|
||||
// Return array
|
||||
var children = [];
|
||||
|
||||
// Iterating
|
||||
for (var i = 0, len = nodeList.length; i < len; ++i) {
|
||||
if (nodeList[i].nodeName !== '#text')
|
||||
children.push(nodeList[i]);
|
||||
}
|
||||
|
||||
return children;
|
||||
},
|
||||
nodeListEach: function(nodeList, func) {
|
||||
|
||||
// Iterating
|
||||
for (var i = 0, len = nodeList.length; i < len; ++i) {
|
||||
if (nodeList[i].nodeName !== '#text')
|
||||
func(nodeList[i]);
|
||||
}
|
||||
},
|
||||
nodeListToHash: function(nodeList, filter) {
|
||||
|
||||
// Return object
|
||||
var children = {};
|
||||
|
||||
// Iterating
|
||||
for (var i = 0; i < nodeList.length; i++) {
|
||||
if (nodeList[i].nodeName !== '#text') {
|
||||
var prop = filter(nodeList[i]);
|
||||
children[prop.key] = prop.value;
|
||||
}
|
||||
}
|
||||
|
||||
return children;
|
||||
},
|
||||
namedNodeMapToObject: function(nodeMap) {
|
||||
|
||||
// Return object
|
||||
var attributes = {};
|
||||
|
||||
// Iterating
|
||||
for (var i = 0; i < nodeMap.length; i++) {
|
||||
attributes[nodeMap[i].name] = nodeMap[i].value;
|
||||
}
|
||||
|
||||
return attributes;
|
||||
},
|
||||
getFirstElementByTagNS: function(node, ns, tag) {
|
||||
var el = node.getElementsByTagName(ns + ':' + tag)[0];
|
||||
|
||||
if (!el)
|
||||
el = node.getElementsByTagNameNS(ns, tag)[0];
|
||||
|
||||
if (!el)
|
||||
el = node.getElementsByTagName(tag)[0];
|
||||
|
||||
return el;
|
||||
},
|
||||
getAttributeNS: function(node, ns, attribute) {
|
||||
var attr_value = node.getAttribute(ns + ':' + attribute);
|
||||
|
||||
if (attr_value === undefined)
|
||||
attr_value = node.getAttributeNS(ns, attribute);
|
||||
|
||||
if (attr_value === undefined)
|
||||
attr_value = node.getAttribute(attribute);
|
||||
|
||||
return attr_value;
|
||||
},
|
||||
enforceType: function(type, value) {
|
||||
|
||||
switch (type) {
|
||||
case 'boolean':
|
||||
value = (value === 'true');
|
||||
break;
|
||||
|
||||
case 'integer':
|
||||
case 'long':
|
||||
case 'float':
|
||||
case 'double':
|
||||
value = +value;
|
||||
break;
|
||||
|
||||
case 'liststring':
|
||||
value = value ? value.split('|') : [];
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
getRGB: function(values) {
|
||||
return (values[3]) ?
|
||||
'rgba(' + values.join(',') + ')' :
|
||||
'rgb(' + values.slice(0, -1).join(',') + ')';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parser Core Functions
|
||||
* ----------------------
|
||||
*
|
||||
* The XML parser's functions themselves.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Node structure.
|
||||
* A function returning an object guarded with default value.
|
||||
*
|
||||
* @param {object} properties The node properties.
|
||||
* @return {object} The guarded node object.
|
||||
*/
|
||||
function Node(properties) {
|
||||
|
||||
// Possible Properties
|
||||
var node = {
|
||||
id: properties.id,
|
||||
label: properties.label
|
||||
};
|
||||
|
||||
if (properties.viz)
|
||||
node.viz = properties.viz;
|
||||
|
||||
if (properties.attributes)
|
||||
node.attributes = properties.attributes;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Edge structure.
|
||||
* A function returning an object guarded with default value.
|
||||
*
|
||||
* @param {object} properties The edge properties.
|
||||
* @return {object} The guarded edge object.
|
||||
*/
|
||||
function Edge(properties) {
|
||||
|
||||
// Possible Properties
|
||||
var edge = {
|
||||
id: properties.id,
|
||||
type: properties.type || 'undirected',
|
||||
label: properties.label || '',
|
||||
source: properties.source,
|
||||
target: properties.target,
|
||||
weight: +properties.weight || 1.0
|
||||
};
|
||||
|
||||
if (properties.viz)
|
||||
edge.viz = properties.viz;
|
||||
|
||||
if (properties.attributes)
|
||||
edge.attributes = properties.attributes;
|
||||
|
||||
return edge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Graph parser.
|
||||
* This structure parse a gexf string and return an object containing the
|
||||
* parsed graph.
|
||||
*
|
||||
* @param {string} xml The xml string of the gexf file to parse.
|
||||
* @return {object} The parsed graph.
|
||||
*/
|
||||
function Graph(xml) {
|
||||
var _xml = {};
|
||||
|
||||
// Basic Properties
|
||||
//------------------
|
||||
_xml.els = {
|
||||
root: xml.getElementsByTagName('gexf')[0],
|
||||
graph: xml.getElementsByTagName('graph')[0],
|
||||
meta: xml.getElementsByTagName('meta')[0],
|
||||
nodes: xml.getElementsByTagName('node'),
|
||||
edges: xml.getElementsByTagName('edge'),
|
||||
model: _helpers.getModelTags(xml)
|
||||
};
|
||||
|
||||
// Information
|
||||
_xml.hasViz = !!_helpers.getAttributeNS(_xml.els.root, 'xmlns', 'viz');
|
||||
_xml.version = _xml.els.root.getAttribute('version') || '1.0';
|
||||
_xml.mode = _xml.els.graph.getAttribute('mode') || 'static';
|
||||
|
||||
var edgeType = _xml.els.graph.getAttribute('defaultedgetype');
|
||||
_xml.defaultEdgetype = edgeType || 'undirected';
|
||||
|
||||
// Parser Functions
|
||||
//------------------
|
||||
|
||||
// Meta Data
|
||||
function _metaData() {
|
||||
|
||||
var metas = {};
|
||||
if (!_xml.els.meta)
|
||||
return metas;
|
||||
|
||||
// Last modified date
|
||||
metas.lastmodifieddate = _xml.els.meta.getAttribute('lastmodifieddate');
|
||||
|
||||
// Other information
|
||||
_helpers.nodeListEach(_xml.els.meta.childNodes, function(child) {
|
||||
metas[child.tagName.toLowerCase()] = child.textContent;
|
||||
});
|
||||
|
||||
return metas;
|
||||
}
|
||||
|
||||
// Model
|
||||
function _model(cls) {
|
||||
var attributes = [];
|
||||
|
||||
// Iterating through attributes
|
||||
if (_xml.els.model[cls])
|
||||
_helpers.nodeListEach(_xml.els.model[cls], function(attr) {
|
||||
|
||||
// Properties
|
||||
var properties = {
|
||||
id: attr.getAttribute('id') || attr.getAttribute('for'),
|
||||
type: attr.getAttribute('type') || 'string',
|
||||
title: attr.getAttribute('title') || ''
|
||||
};
|
||||
|
||||
// Defaults
|
||||
var default_el = _helpers.nodeListToArray(attr.childNodes);
|
||||
|
||||
if (default_el.length > 0)
|
||||
properties.defaultValue = default_el[0].textContent;
|
||||
|
||||
// Creating attribute
|
||||
attributes.push(properties);
|
||||
});
|
||||
|
||||
return attributes.length > 0 ? attributes : false;
|
||||
}
|
||||
|
||||
// Data from nodes or edges
|
||||
function _data(model, node_or_edge) {
|
||||
|
||||
var data = {};
|
||||
var attvalues_els = node_or_edge.getElementsByTagName('attvalue');
|
||||
|
||||
// Getting Node Indicated Attributes
|
||||
var ah = _helpers.nodeListToHash(attvalues_els, function(el) {
|
||||
var attributes = _helpers.namedNodeMapToObject(el.attributes);
|
||||
var key = attributes.id || attributes['for'];
|
||||
|
||||
// Returning object
|
||||
return {key: key, value: attributes.value};
|
||||
});
|
||||
|
||||
|
||||
// Iterating through model
|
||||
model.map(function(a) {
|
||||
|
||||
// Default value?
|
||||
data[a.id] = !(a.id in ah) && 'defaultValue' in a ?
|
||||
_helpers.enforceType(a.type, a.defaultValue) :
|
||||
_helpers.enforceType(a.type, ah[a.id]);
|
||||
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Nodes
|
||||
function _nodes(model) {
|
||||
var nodes = [];
|
||||
|
||||
// Iteration through nodes
|
||||
_helpers.nodeListEach(_xml.els.nodes, function(n) {
|
||||
|
||||
// Basic properties
|
||||
var properties = {
|
||||
id: n.getAttribute('id'),
|
||||
label: n.getAttribute('label') || ''
|
||||
};
|
||||
|
||||
// Retrieving data from nodes if any
|
||||
if (model)
|
||||
properties.attributes = _data(model, n);
|
||||
|
||||
// Retrieving viz information
|
||||
if (_xml.hasViz)
|
||||
properties.viz = _nodeViz(n);
|
||||
|
||||
// Pushing node
|
||||
nodes.push(Node(properties));
|
||||
});
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
// Viz information from nodes
|
||||
function _nodeViz(node) {
|
||||
var viz = {};
|
||||
|
||||
// Color
|
||||
var color_el = _helpers.getFirstElementByTagNS(node, 'viz', 'color');
|
||||
|
||||
if (color_el) {
|
||||
var color = ['r', 'g', 'b', 'a'].map(function(c) {
|
||||
return color_el.getAttribute(c);
|
||||
});
|
||||
|
||||
viz.color = _helpers.getRGB(color);
|
||||
}
|
||||
|
||||
// Position
|
||||
var pos_el = _helpers.getFirstElementByTagNS(node, 'viz', 'position');
|
||||
|
||||
if (pos_el) {
|
||||
viz.position = {};
|
||||
|
||||
['x', 'y', 'z'].map(function(p) {
|
||||
viz.position[p] = +pos_el.getAttribute(p);
|
||||
});
|
||||
}
|
||||
|
||||
// Size
|
||||
var size_el = _helpers.getFirstElementByTagNS(node, 'viz', 'size');
|
||||
if (size_el)
|
||||
viz.size = +size_el.getAttribute('value');
|
||||
|
||||
// Shape
|
||||
var shape_el = _helpers.getFirstElementByTagNS(node, 'viz', 'shape');
|
||||
if (shape_el)
|
||||
viz.shape = shape_el.getAttribute('value');
|
||||
|
||||
return viz;
|
||||
}
|
||||
|
||||
// Edges
|
||||
function _edges(model, default_type) {
|
||||
var edges = [];
|
||||
|
||||
// Iteration through edges
|
||||
_helpers.nodeListEach(_xml.els.edges, function(e) {
|
||||
|
||||
// Creating the edge
|
||||
var properties = _helpers.namedNodeMapToObject(e.attributes);
|
||||
if (!('type' in properties)) {
|
||||
properties.type = default_type;
|
||||
}
|
||||
|
||||
// Retrieving edge data
|
||||
if (model)
|
||||
properties.attributes = _data(model, e);
|
||||
|
||||
|
||||
// Retrieving viz information
|
||||
if (_xml.hasViz)
|
||||
properties.viz = _edgeViz(e);
|
||||
|
||||
edges.push(Edge(properties));
|
||||
});
|
||||
|
||||
return edges;
|
||||
}
|
||||
|
||||
// Viz information from edges
|
||||
function _edgeViz(edge) {
|
||||
var viz = {};
|
||||
|
||||
// Color
|
||||
var color_el = _helpers.getFirstElementByTagNS(edge, 'viz', 'color');
|
||||
|
||||
if (color_el) {
|
||||
var color = ['r', 'g', 'b', 'a'].map(function(c) {
|
||||
return color_el.getAttribute(c);
|
||||
});
|
||||
|
||||
viz.color = _helpers.getRGB(color);
|
||||
}
|
||||
|
||||
// Shape
|
||||
var shape_el = _helpers.getFirstElementByTagNS(edge, 'viz', 'shape');
|
||||
if (shape_el)
|
||||
viz.shape = shape_el.getAttribute('value');
|
||||
|
||||
// Thickness
|
||||
var thick_el = _helpers.getFirstElementByTagNS(edge, 'viz', 'thickness');
|
||||
if (thick_el)
|
||||
viz.thickness = +thick_el.getAttribute('value');
|
||||
|
||||
return viz;
|
||||
}
|
||||
|
||||
|
||||
// Returning the Graph
|
||||
//---------------------
|
||||
var nodeModel = _model('node'),
|
||||
edgeModel = _model('edge');
|
||||
|
||||
var graph = {
|
||||
version: _xml.version,
|
||||
mode: _xml.mode,
|
||||
defaultEdgeType: _xml.defaultEdgetype,
|
||||
meta: _metaData(),
|
||||
model: {},
|
||||
nodes: _nodes(nodeModel),
|
||||
edges: _edges(edgeModel, _xml.defaultEdgetype)
|
||||
};
|
||||
|
||||
if (nodeModel)
|
||||
graph.model.node = nodeModel;
|
||||
if (edgeModel)
|
||||
graph.model.edge = edgeModel;
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Public API
|
||||
* -----------
|
||||
*
|
||||
* User-accessible functions.
|
||||
*/
|
||||
|
||||
// Fetching GEXF with XHR
|
||||
function fetch(gexf_url, callback) {
|
||||
var xhr = (function() {
|
||||
if (window.XMLHttpRequest)
|
||||
return new XMLHttpRequest();
|
||||
|
||||
var names,
|
||||
i;
|
||||
|
||||
if (window.ActiveXObject) {
|
||||
names = [
|
||||
'Msxml2.XMLHTTP.6.0',
|
||||
'Msxml2.XMLHTTP.3.0',
|
||||
'Msxml2.XMLHTTP',
|
||||
'Microsoft.XMLHTTP'
|
||||
];
|
||||
|
||||
for (i in names)
|
||||
try {
|
||||
return new ActiveXObject(names[i]);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
return null;
|
||||
})();
|
||||
|
||||
if (!xhr)
|
||||
throw 'XMLHttpRequest not supported, cannot load the file.';
|
||||
|
||||
// Async?
|
||||
var async = (typeof callback === 'function'),
|
||||
getResult;
|
||||
|
||||
// If we can't override MIME type, we are on IE 9
|
||||
// We'll be parsing the response string then.
|
||||
if (xhr.overrideMimeType) {
|
||||
xhr.overrideMimeType('text/xml');
|
||||
getResult = function(r) {
|
||||
return r.responseXML;
|
||||
};
|
||||
}
|
||||
else {
|
||||
getResult = function(r) {
|
||||
var p = new DOMParser();
|
||||
return p.parseFromString(r.responseText, 'application/xml');
|
||||
};
|
||||
}
|
||||
|
||||
xhr.open('GET', gexf_url, async);
|
||||
|
||||
if (async)
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === 4)
|
||||
callback(getResult(xhr));
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
|
||||
return (async) ? xhr : getResult(xhr);
|
||||
}
|
||||
|
||||
// Parsing the GEXF File
|
||||
function parse(gexf) {
|
||||
return Graph(gexf);
|
||||
}
|
||||
|
||||
// Fetch and parse the GEXF File
|
||||
function fetchAndParse(gexf_url, callback) {
|
||||
if (typeof callback === 'function') {
|
||||
return fetch(gexf_url, function(gexf) {
|
||||
callback(Graph(gexf));
|
||||
});
|
||||
} else
|
||||
return Graph(fetch(gexf_url));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Exporting
|
||||
* ----------
|
||||
*/
|
||||
if (typeof this.gexf !== 'undefined')
|
||||
throw 'gexf: error - a variable called "gexf" already ' +
|
||||
'exists in the global scope';
|
||||
|
||||
this.gexf = {
|
||||
|
||||
// Functions
|
||||
parse: parse,
|
||||
fetch: fetchAndParse,
|
||||
|
||||
// Version
|
||||
version: '0.1.1'
|
||||
};
|
||||
|
||||
if (typeof exports !== 'undefined' && this.exports !== exports)
|
||||
module.exports = this.gexf;
|
||||
}).call(this);
|
|
@ -0,0 +1,112 @@
|
|||
;(function(undefined) {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined')
|
||||
throw 'sigma is not declared';
|
||||
|
||||
// Initialize package:
|
||||
sigma.utils.pkg('sigma.parsers');
|
||||
|
||||
// Just a basic ID generator:
|
||||
var _id = 0;
|
||||
function edgeId() {
|
||||
return 'e' + (_id++);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the first arguments is a valid URL, this function loads a GEXF file and
|
||||
* creates a new sigma instance or updates the graph of a given instance. It
|
||||
* is possible to give a callback that will be executed at the end of the
|
||||
* process. And if the first argument is a DOM element, it will skip the
|
||||
* loading step and parse the given XML tree to fill the graph.
|
||||
*
|
||||
* @param {string|DOMElement} target The URL of the GEXF file or a valid
|
||||
* GEXF tree.
|
||||
* @param {object|sigma} sig A sigma configuration object or a
|
||||
* sigma instance.
|
||||
* @param {?function} callback Eventually a callback to execute
|
||||
* after having parsed the file. It will
|
||||
* be called with the related sigma
|
||||
* instance as parameter.
|
||||
*/
|
||||
sigma.parsers.gexf = function(target, sig, callback) {
|
||||
var i,
|
||||
l,
|
||||
arr,
|
||||
obj;
|
||||
|
||||
function parse(graph) {
|
||||
// Adapt the graph:
|
||||
arr = graph.nodes;
|
||||
for (i = 0, l = arr.length; i < l; i++) {
|
||||
obj = arr[i];
|
||||
|
||||
obj.id = obj.id;
|
||||
if (obj.viz && typeof obj.viz === 'object') {
|
||||
if (obj.viz.position && typeof obj.viz.position === 'object') {
|
||||
obj.x = obj.viz.position.x;
|
||||
obj.y = -obj.viz.position.y; // Needed otherwise it's up side down
|
||||
}
|
||||
obj.size = obj.viz.size;
|
||||
obj.color = obj.viz.color;
|
||||
}
|
||||
}
|
||||
|
||||
arr = graph.edges;
|
||||
for (i = 0, l = arr.length; i < l; i++) {
|
||||
obj = arr[i];
|
||||
|
||||
obj.id = typeof obj.id === 'string' ? obj.id : edgeId();
|
||||
obj.source = '' + obj.source;
|
||||
obj.target = '' + obj.target;
|
||||
|
||||
if (obj.viz && typeof obj.viz === 'object') {
|
||||
obj.color = obj.viz.color;
|
||||
obj.size = obj.viz.thickness;
|
||||
}
|
||||
|
||||
// Weight over viz.thickness?
|
||||
obj.size = obj.weight;
|
||||
|
||||
// Changing type to be direction so it won't mess with sigma's naming
|
||||
obj.direction = obj.type;
|
||||
delete obj.type;
|
||||
}
|
||||
|
||||
// Update the instance's graph:
|
||||
if (sig instanceof sigma) {
|
||||
sig.graph.clear();
|
||||
|
||||
arr = graph.nodes;
|
||||
for (i = 0, l = arr.length; i < l; i++)
|
||||
sig.graph.addNode(arr[i]);
|
||||
|
||||
arr = graph.edges;
|
||||
for (i = 0, l = arr.length; i < l; i++)
|
||||
sig.graph.addEdge(arr[i]);
|
||||
|
||||
// ...or instantiate sigma if needed:
|
||||
} else if (typeof sig === 'object') {
|
||||
sig.graph = graph;
|
||||
sig = new sigma(sig);
|
||||
|
||||
// ...or it's finally the callback:
|
||||
} else if (typeof sig === 'function') {
|
||||
callback = sig;
|
||||
sig = null;
|
||||
}
|
||||
|
||||
// Call the callback if specified:
|
||||
if (callback) {
|
||||
callback(sig || graph);
|
||||
return;
|
||||
} else
|
||||
return graph;
|
||||
}
|
||||
|
||||
if (typeof target === 'string')
|
||||
gexf.fetch(target, parse);
|
||||
else if (typeof target === 'object')
|
||||
return parse(gexf.parse(target));
|
||||
};
|
||||
}).call(this);
|
|
@ -0,0 +1,29 @@
|
|||
sigma.parsers.json
|
||||
==================
|
||||
|
||||
Plugin developed by [Alexis Jacomy](https://github.com/jacomyal).
|
||||
|
||||
---
|
||||
|
||||
This plugin provides a single function, `sigma.parsers.json()`, that will load a JSON encoded file, parse it, eventually instantiate sigma and fill the graph with the `graph.read()` method. The main goal is to avoid using jQuery only to load an external JSON file.
|
||||
|
||||
The most basic way to use this helper is to call it with a path and a sigma configuration object. It will then instanciate sigma, but after having added the graph into the config object.
|
||||
|
||||
````javascript
|
||||
sigma.parsers.json(
|
||||
'myGraph.json',
|
||||
{ container: 'myContainer' }
|
||||
);
|
||||
````
|
||||
|
||||
It is also possible to update an existing instance's graph instead.
|
||||
|
||||
````javascript
|
||||
sigma.parsers.json(
|
||||
'myGraph.json',
|
||||
myExistingInstance,
|
||||
function() {
|
||||
myExistingInstance.refresh();
|
||||
}
|
||||
);
|
||||
````
|
|
@ -0,0 +1,88 @@
|
|||
;(function(undefined) {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined')
|
||||
throw 'sigma is not declared';
|
||||
|
||||
// Initialize package:
|
||||
sigma.utils.pkg('sigma.parsers');
|
||||
sigma.utils.pkg('sigma.utils');
|
||||
|
||||
/**
|
||||
* Just an XmlHttpRequest polyfill for different IE versions.
|
||||
*
|
||||
* @return {*} The XHR like object.
|
||||
*/
|
||||
sigma.utils.xhr = function() {
|
||||
if (window.XMLHttpRequest)
|
||||
return new XMLHttpRequest();
|
||||
|
||||
var names,
|
||||
i;
|
||||
|
||||
if (window.ActiveXObject) {
|
||||
names = [
|
||||
'Msxml2.XMLHTTP.6.0',
|
||||
'Msxml2.XMLHTTP.3.0',
|
||||
'Msxml2.XMLHTTP',
|
||||
'Microsoft.XMLHTTP'
|
||||
];
|
||||
|
||||
for (i in names)
|
||||
try {
|
||||
return new ActiveXObject(names[i]);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* This function loads a JSON file and creates a new sigma instance or
|
||||
* updates the graph of a given instance. It is possible to give a callback
|
||||
* that will be executed at the end of the process.
|
||||
*
|
||||
* @param {string} url The URL of the JSON file.
|
||||
* @param {object|sigma} sig A sigma configuration object or a sigma
|
||||
* instance.
|
||||
* @param {?function} callback Eventually a callback to execute after
|
||||
* having parsed the file. It will be called
|
||||
* with the related sigma instance as
|
||||
* parameter.
|
||||
*/
|
||||
sigma.parsers.json = function(url, sig, callback) {
|
||||
var graph,
|
||||
xhr = sigma.utils.xhr();
|
||||
|
||||
if (!xhr)
|
||||
throw 'XMLHttpRequest not supported, cannot load the file.';
|
||||
|
||||
xhr.open('GET', url, true);
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === 4) {
|
||||
graph = JSON.parse(xhr.responseText);
|
||||
|
||||
// Update the instance's graph:
|
||||
if (sig instanceof sigma) {
|
||||
sig.graph.clear();
|
||||
sig.graph.read(graph);
|
||||
|
||||
// ...or instantiate sigma if needed:
|
||||
} else if (typeof sig === 'object') {
|
||||
sig.graph = graph;
|
||||
sig = new sigma(sig);
|
||||
|
||||
// ...or it's finally the callback:
|
||||
} else if (typeof sig === 'function') {
|
||||
callback = sig;
|
||||
sig = null;
|
||||
}
|
||||
|
||||
// Call the callback if specified:
|
||||
if (callback)
|
||||
callback(sig || graph);
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
};
|
||||
}).call(this);
|
|
@ -0,0 +1,25 @@
|
|||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
sigma.pathfinding.astar.js — v1.0.0
|
||||
===================================
|
||||
|
||||
> Plugin author: [@A----](https://github.com/A----)
|
||||
> Main repository for this plugin is here: https://github.com/A----/sigma-pathfinding-astar
|
||||
> Please report issues, make PR, there.
|
||||
> This project is released under Public Domain license (see LICENSE for more information).
|
||||
|
||||
|
||||
*sigma.pathfinding.astar.js* is a plugin for [sigma.js](http://sigmajs.org) that computes path in a graph
|
||||
using a naive implementation of the [A*](http://en.wikipedia.org/wiki/A*_search_algorithm) algorithm.
|
||||
|
||||
## Usage
|
||||
|
||||
Either download a tarball, `git clone` the repository or `npm install` it. Then it's pretty straight-forward.
|
||||
|
||||
It adds a method to your `sigma.graph` called `astar(srcId, destId[, options])`.
|
||||
- `srcId`, identifier of the start node;
|
||||
- `destId`, identification of the destination node;
|
||||
- `options` (optional), an object containing one or more of those properties:
|
||||
- `undirected` (default: `false`), if set to `true`, consider the graph as non-oriented (will explore all edges, including the inbound ones);
|
||||
- `pathLengthFunction` (default is the geometrical distance), a `function(node1, node2, previousLength)` that should return the new path length between the start node and `node2`, knowing that the path length between the start node and `node1` is contained in `previousLength`.
|
||||
- `heuristicLengthFunction` (default: `undefined`), a `function(node1, node2)` guesses the path length between `node1` and `node2` (`node2` actually is the destination node). If left undefined, takes the `pathLengthFunction` option (third parameter will be left undefined).
|
||||
|
||||
Return value is either:
|
||||
- `undefined`: no path could be found between the source node and the destination node;
|
||||
- `[srcNode, …, destNode ]`: an array of nodes, including source and destination node.
|
|
@ -0,0 +1,134 @@
|
|||
(function() {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined') {
|
||||
throw 'sigma is not declared';
|
||||
}
|
||||
|
||||
// Default function to compute path length between two nodes:
|
||||
// the euclidian
|
||||
var defaultPathLengthFunction = function(node1, node2, previousPathLength) {
|
||||
var isEverythingDefined =
|
||||
node1 != undefined &&
|
||||
node2 != undefined &&
|
||||
node1.x != undefined &&
|
||||
node1.y != undefined &&
|
||||
node2.x != undefined &&
|
||||
node2.y != undefined;
|
||||
if(!isEverythingDefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return (previousPathLength || 0) + Math.sqrt(
|
||||
Math.pow((node2.y - node1.y), 2) + Math.pow((node2.x - node1.x), 2)
|
||||
);
|
||||
};
|
||||
|
||||
sigma.classes.graph.addMethod(
|
||||
'astar',
|
||||
function(srcId, destId, settings) {
|
||||
var currentSettings = new sigma.classes.configurable(
|
||||
// Default settings
|
||||
{
|
||||
// Graph is directed, affects which edges are taken into account
|
||||
undirected: false,
|
||||
// Function to compute the distance between two connected node
|
||||
pathLengthFunction: defaultPathLengthFunction,
|
||||
// Function to compute an distance between two nodes
|
||||
// if undefined, uses pathLengthFunction
|
||||
heuristicLengthFunction: undefined
|
||||
},
|
||||
settings || {});
|
||||
|
||||
var pathLengthFunction = currentSettings("pathLengthFunction"),
|
||||
heuristicLengthFunction = currentSettings("heuristicLengthFunction") || pathLengthFunction;
|
||||
|
||||
var srcNode = this.nodes(srcId),
|
||||
destNode = this.nodes(destId);
|
||||
|
||||
var closedList = {},
|
||||
openList = [];
|
||||
|
||||
var addToLists = function(node, previousNode, pathLength, heuristicLength) {
|
||||
var nodeId = node.id;
|
||||
var newItem = {
|
||||
pathLength: pathLength,
|
||||
heuristicLength: heuristicLength,
|
||||
node: node,
|
||||
nodeId: nodeId,
|
||||
previousNode: previousNode
|
||||
};
|
||||
|
||||
if(closedList[nodeId] == undefined || closedList[nodeId].pathLength > pathLength) {
|
||||
closedList[nodeId] = newItem;
|
||||
|
||||
var item;
|
||||
var i;
|
||||
for(i = 0; i < openList.length; i++) {
|
||||
item = openList[i];
|
||||
if(item.heuristicLength > heuristicLength) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
openList.splice(i, 0, newItem);
|
||||
}
|
||||
};
|
||||
|
||||
addToLists(srcNode, null, 0, 0);
|
||||
|
||||
var pathFound = false;
|
||||
|
||||
// Depending of the type of graph (directed or not),
|
||||
// the neighbors are either the out neighbors or all.
|
||||
var allNeighbors;
|
||||
if(currentSettings("undirected")) {
|
||||
allNeighbors = this.allNeighborsIndex;
|
||||
}
|
||||
else {
|
||||
allNeighbors = this.outNeighborsIndex;
|
||||
}
|
||||
|
||||
|
||||
var inspectedItem,
|
||||
neighbors,
|
||||
neighbor,
|
||||
pathLength,
|
||||
heuristicLength,
|
||||
i;
|
||||
while(openList.length > 0) {
|
||||
inspectedItem = openList.shift();
|
||||
|
||||
// We reached the destination node
|
||||
if(inspectedItem.nodeId == destId) {
|
||||
pathFound = true;
|
||||
break;
|
||||
}
|
||||
|
||||
neighbors = Object.keys(allNeighbors[inspectedItem.nodeId]);
|
||||
for(i = 0; i < neighbors.length; i++) {
|
||||
neighbor = this.nodes(neighbors[i]);
|
||||
pathLength = pathLengthFunction(inspectedItem.node, neighbor, inspectedItem.pathLength);
|
||||
heuristicLength = heuristicLengthFunction(neighbor, destNode);
|
||||
addToLists(neighbor, inspectedItem.node, pathLength, heuristicLength);
|
||||
}
|
||||
}
|
||||
|
||||
if(pathFound) {
|
||||
// Rebuilding path
|
||||
var path = [],
|
||||
currentNode = destNode;
|
||||
|
||||
while(currentNode) {
|
||||
path.unshift(currentNode);
|
||||
currentNode = closedList[currentNode.id].previousNode;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
);
|
||||
}).call(window);
|
|
@ -0,0 +1,71 @@
|
|||
sigma.plugins.animate
|
||||
=====================
|
||||
|
||||
Plugin developed by [Alexis Jacomy](https://github.com/jacomyal).
|
||||
|
||||
---
|
||||
|
||||
This plugin provides a method to animate a sigma instance by interpolating some node properties. Check the `sigma.plugins.animate` function doc or the `examples/animate.html` code sample to know more.
|
||||
|
||||
Interpolate coordinates as follows:
|
||||
|
||||
```js
|
||||
sigma.plugins.animate(
|
||||
s,
|
||||
{
|
||||
x: 'target_x',
|
||||
y: 'target_y',
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Interpolate colors and sizes as follows:
|
||||
|
||||
```js
|
||||
sigma.plugins.animate(
|
||||
s,
|
||||
{
|
||||
size: 'target_size',
|
||||
color: 'target_color'
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Animate a subset of nodes as follows:
|
||||
|
||||
```js
|
||||
sigma.plugins.animate(
|
||||
s,
|
||||
{
|
||||
x: 'to_x',
|
||||
y: 'to_y',
|
||||
size: 'to_size',
|
||||
color: 'to_color'
|
||||
},
|
||||
{
|
||||
nodes: ['n0', 'n1', 'n2']
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Example using all options:
|
||||
|
||||
```js
|
||||
sigma.plugins.animate(
|
||||
s,
|
||||
{
|
||||
x: 'to_x',
|
||||
y: 'to_y',
|
||||
size: 'to_size',
|
||||
color: 'to_color'
|
||||
},
|
||||
{
|
||||
nodes: ['n0', 'n1', 'n2'],
|
||||
easing: 'cubicInOut',
|
||||
duration: 300,
|
||||
onComplete: function() {
|
||||
// do stuff here after animation is complete
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
|
@ -0,0 +1,204 @@
|
|||
/**
|
||||
* This plugin provides a method to animate a sigma instance by interpolating
|
||||
* some node properties. Check the sigma.plugins.animate function doc or the
|
||||
* examples/animate.html code sample to know more.
|
||||
*/
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined')
|
||||
throw 'sigma is not declared';
|
||||
|
||||
sigma.utils.pkg('sigma.plugins');
|
||||
|
||||
var _id = 0,
|
||||
_cache = {};
|
||||
|
||||
// TOOLING FUNCTIONS:
|
||||
// ******************
|
||||
function parseColor(val) {
|
||||
if (_cache[val])
|
||||
return _cache[val];
|
||||
|
||||
var result = [0, 0, 0];
|
||||
|
||||
if (val.match(/^#/)) {
|
||||
val = (val || '').replace(/^#/, '');
|
||||
result = (val.length === 3) ?
|
||||
[
|
||||
parseInt(val.charAt(0) + val.charAt(0), 16),
|
||||
parseInt(val.charAt(1) + val.charAt(1), 16),
|
||||
parseInt(val.charAt(2) + val.charAt(2), 16)
|
||||
] :
|
||||
[
|
||||
parseInt(val.charAt(0) + val.charAt(1), 16),
|
||||
parseInt(val.charAt(2) + val.charAt(3), 16),
|
||||
parseInt(val.charAt(4) + val.charAt(5), 16)
|
||||
];
|
||||
} else if (val.match(/^ *rgba? *\(/)) {
|
||||
val = val.match(
|
||||
/^ *rgba? *\( *([0-9]*) *, *([0-9]*) *, *([0-9]*) *(,.*)?\) *$/
|
||||
);
|
||||
result = [
|
||||
+val[1],
|
||||
+val[2],
|
||||
+val[3]
|
||||
];
|
||||
}
|
||||
|
||||
_cache[val] = {
|
||||
r: result[0],
|
||||
g: result[1],
|
||||
b: result[2]
|
||||
};
|
||||
|
||||
return _cache[val];
|
||||
}
|
||||
|
||||
function interpolateColors(c1, c2, p) {
|
||||
c1 = parseColor(c1);
|
||||
c2 = parseColor(c2);
|
||||
|
||||
var c = {
|
||||
r: c1.r * (1 - p) + c2.r * p,
|
||||
g: c1.g * (1 - p) + c2.g * p,
|
||||
b: c1.b * (1 - p) + c2.b * p
|
||||
};
|
||||
|
||||
return 'rgb(' + [c.r | 0, c.g | 0, c.b | 0].join(',') + ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will animate some specified node properties. It will
|
||||
* basically call requestAnimationFrame, interpolate the values and call the
|
||||
* refresh method during a specified duration.
|
||||
*
|
||||
* Recognized parameters:
|
||||
* **********************
|
||||
* Here is the exhaustive list of every accepted parameters in the settings
|
||||
* object:
|
||||
*
|
||||
* {?array} nodes An array of node objects or node ids. If
|
||||
* not specified, all nodes of the graph
|
||||
* will be animated.
|
||||
* {?(function|string)} easing Either the name of an easing in the
|
||||
* sigma.utils.easings package or a
|
||||
* function. If not specified, the
|
||||
* quadraticInOut easing from this package
|
||||
* will be used instead.
|
||||
* {?number} duration The duration of the animation. If not
|
||||
* specified, the "animationsTime" setting
|
||||
* value of the sigma instance will be used
|
||||
* instead.
|
||||
* {?function} onComplete Eventually a function to call when the
|
||||
* animation is ended.
|
||||
*
|
||||
* @param {sigma} s The related sigma instance.
|
||||
* @param {object} animate An hash with the keys being the node properties
|
||||
* to interpolate, and the values being the related
|
||||
* target values.
|
||||
* @param {?object} options Eventually an object with options.
|
||||
*/
|
||||
sigma.plugins.animate = function(s, animate, options) {
|
||||
var o = options || {},
|
||||
id = ++_id,
|
||||
duration = o.duration || s.settings('animationsTime'),
|
||||
easing = typeof o.easing === 'string' ?
|
||||
sigma.utils.easings[o.easing] :
|
||||
typeof o.easing === 'function' ?
|
||||
o.easing :
|
||||
sigma.utils.easings.quadraticInOut,
|
||||
start = sigma.utils.dateNow(),
|
||||
nodes,
|
||||
startPositions;
|
||||
|
||||
if (o.nodes && o.nodes.length) {
|
||||
if (typeof o.nodes[0] === 'object')
|
||||
nodes = o.nodes;
|
||||
else
|
||||
nodes = s.graph.nodes(o.nodes); // argument is an array of IDs
|
||||
}
|
||||
else
|
||||
nodes = s.graph.nodes();
|
||||
|
||||
// Store initial positions:
|
||||
startPositions = nodes.reduce(function(res, node) {
|
||||
var k;
|
||||
res[node.id] = {};
|
||||
for (k in animate)
|
||||
if (k in node)
|
||||
res[node.id][k] = node[k];
|
||||
return res;
|
||||
}, {});
|
||||
|
||||
s.animations = s.animations || Object.create({});
|
||||
sigma.plugins.kill(s);
|
||||
|
||||
// Do not refresh edgequadtree during drag:
|
||||
var k,
|
||||
c;
|
||||
for (k in s.cameras) {
|
||||
c = s.cameras[k];
|
||||
c.edgequadtree._enabled = false;
|
||||
}
|
||||
|
||||
function step() {
|
||||
var p = (sigma.utils.dateNow() - start) / duration;
|
||||
|
||||
if (p >= 1) {
|
||||
nodes.forEach(function(node) {
|
||||
for (var k in animate)
|
||||
if (k in animate)
|
||||
node[k] = node[animate[k]];
|
||||
});
|
||||
|
||||
// Allow to refresh edgequadtree:
|
||||
var k,
|
||||
c;
|
||||
for (k in s.cameras) {
|
||||
c = s.cameras[k];
|
||||
c.edgequadtree._enabled = true;
|
||||
}
|
||||
|
||||
s.refresh();
|
||||
if (typeof o.onComplete === 'function')
|
||||
o.onComplete();
|
||||
} else {
|
||||
p = easing(p);
|
||||
nodes.forEach(function(node) {
|
||||
for (var k in animate)
|
||||
if (k in animate) {
|
||||
if (k.match(/color$/))
|
||||
node[k] = interpolateColors(
|
||||
startPositions[node.id][k],
|
||||
node[animate[k]],
|
||||
p
|
||||
);
|
||||
else
|
||||
node[k] =
|
||||
node[animate[k]] * p +
|
||||
startPositions[node.id][k] * (1 - p);
|
||||
}
|
||||
});
|
||||
|
||||
s.refresh();
|
||||
s.animations[id] = requestAnimationFrame(step);
|
||||
}
|
||||
}
|
||||
|
||||
step();
|
||||
};
|
||||
|
||||
sigma.plugins.kill = function(s) {
|
||||
for (var k in (s.animations || {}))
|
||||
cancelAnimationFrame(s.animations[k]);
|
||||
|
||||
// Allow to refresh edgequadtree:
|
||||
var k,
|
||||
c;
|
||||
for (k in s.cameras) {
|
||||
c = s.cameras[k];
|
||||
c.edgequadtree._enabled = true;
|
||||
}
|
||||
};
|
||||
}).call(window);
|
|
@ -0,0 +1,36 @@
|
|||
sigma.plugins.dragNodes
|
||||
=====================
|
||||
|
||||
Plugin developed by [José M. Camacho](https://github.com/josemazo), events by [Sébastien Heymann](https://github.com/sheymann) for [Linkurious](https://github.com/Linkurious).
|
||||
|
||||
---
|
||||
|
||||
This plugin provides a method to drag & drop nodes. At the moment, this plugin is not compatible with the WebGL renderer. Check the sigma.plugins.dragNodes function doc or the [example code](../../examples/drag-nodes.html) to know more.
|
||||
|
||||
To use, include all .js files under this folder. Then initialize it as follows:
|
||||
|
||||
````javascript
|
||||
var dragListener = new sigma.plugins.dragNodes(sigInst, renderer);
|
||||
````
|
||||
|
||||
Kill the plugin as follows:
|
||||
|
||||
````javascript
|
||||
sigma.plugins.killDragNodes(sigInst);
|
||||
````
|
||||
|
||||
## Events
|
||||
|
||||
This plugin provides the following events fired by the instance of the plugin:
|
||||
* `startdrag`: fired at the beginning of the drag
|
||||
* `drag`: fired while the node is dragged
|
||||
* `drop`: fired at the end of the drag if the node has been dragged
|
||||
* `dragend`: fired at the end of the drag
|
||||
|
||||
Exemple of event binding:
|
||||
|
||||
````javascript
|
||||
dragListener.bind('startdrag', function(event) {
|
||||
console.log(event);
|
||||
});
|
||||
````
|
|
@ -0,0 +1,326 @@
|
|||
/**
|
||||
* This plugin provides a method to drag & drop nodes. Check the
|
||||
* sigma.plugins.dragNodes function doc or the examples/basic.html &
|
||||
* examples/api-candy.html code samples to know more.
|
||||
*/
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined')
|
||||
throw 'sigma is not declared';
|
||||
|
||||
sigma.utils.pkg('sigma.plugins');
|
||||
|
||||
|
||||
/**
|
||||
* This function will add `mousedown`, `mouseup` & `mousemove` events to the
|
||||
* nodes in the `overNode`event to perform drag & drop operations. It uses
|
||||
* `linear interpolation` [http://en.wikipedia.org/wiki/Linear_interpolation]
|
||||
* and `rotation matrix` [http://en.wikipedia.org/wiki/Rotation_matrix] to
|
||||
* calculate the X and Y coordinates from the `cam` or `renderer` node
|
||||
* attributes. These attributes represent the coordinates of the nodes in
|
||||
* the real container, not in canvas.
|
||||
*
|
||||
* Fired events:
|
||||
* *************
|
||||
* startdrag Fired at the beginning of the drag.
|
||||
* drag Fired while the node is dragged.
|
||||
* drop Fired at the end of the drag if the node has been dragged.
|
||||
* dragend Fired at the end of the drag.
|
||||
*
|
||||
* Recognized parameters:
|
||||
* **********************
|
||||
* @param {sigma} s The related sigma instance.
|
||||
* @param {renderer} renderer The related renderer instance.
|
||||
*/
|
||||
function DragNodes(s, renderer) {
|
||||
sigma.classes.dispatcher.extend(this);
|
||||
|
||||
// A quick hardcoded rule to prevent people from using this plugin with the
|
||||
// WebGL renderer (which is impossible at the moment):
|
||||
// if (
|
||||
// sigma.renderers.webgl &&
|
||||
// renderer instanceof sigma.renderers.webgl
|
||||
// )
|
||||
// throw new Error(
|
||||
// 'The sigma.plugins.dragNodes is not compatible with the WebGL renderer'
|
||||
// );
|
||||
|
||||
// Init variables:
|
||||
var _self = this,
|
||||
_s = s,
|
||||
_body = document.body,
|
||||
_renderer = renderer,
|
||||
_mouse = renderer.container.lastChild,
|
||||
_camera = renderer.camera,
|
||||
_node = null,
|
||||
_prefix = '',
|
||||
_hoverStack = [],
|
||||
_hoverIndex = {},
|
||||
_isMouseDown = false,
|
||||
_isMouseOverCanvas = false,
|
||||
_drag = false;
|
||||
|
||||
if (renderer instanceof sigma.renderers.svg) {
|
||||
_mouse = renderer.container.firstChild;
|
||||
}
|
||||
|
||||
// It removes the initial substring ('read_') if it's a WegGL renderer.
|
||||
if (renderer instanceof sigma.renderers.webgl) {
|
||||
_prefix = renderer.options.prefix.substr(5);
|
||||
} else {
|
||||
_prefix = renderer.options.prefix;
|
||||
}
|
||||
|
||||
renderer.bind('overNode', nodeMouseOver);
|
||||
renderer.bind('outNode', treatOutNode);
|
||||
renderer.bind('click', click);
|
||||
|
||||
_s.bind('kill', function() {
|
||||
_self.unbindAll();
|
||||
});
|
||||
|
||||
/**
|
||||
* Unbind all event listeners.
|
||||
*/
|
||||
this.unbindAll = function() {
|
||||
_mouse.removeEventListener('mousedown', nodeMouseDown);
|
||||
_body.removeEventListener('mousemove', nodeMouseMove);
|
||||
_body.removeEventListener('mouseup', nodeMouseUp);
|
||||
_renderer.unbind('overNode', nodeMouseOver);
|
||||
_renderer.unbind('outNode', treatOutNode);
|
||||
}
|
||||
|
||||
// Calculates the global offset of the given element more accurately than
|
||||
// element.offsetTop and element.offsetLeft.
|
||||
function calculateOffset(element) {
|
||||
var style = window.getComputedStyle(element);
|
||||
var getCssProperty = function(prop) {
|
||||
return parseInt(style.getPropertyValue(prop).replace('px', '')) || 0;
|
||||
};
|
||||
return {
|
||||
left: element.getBoundingClientRect().left + getCssProperty('padding-left'),
|
||||
top: element.getBoundingClientRect().top + getCssProperty('padding-top')
|
||||
};
|
||||
};
|
||||
|
||||
function click(event) {
|
||||
// event triggered at the end of the click
|
||||
_isMouseDown = false;
|
||||
_body.removeEventListener('mousemove', nodeMouseMove);
|
||||
_body.removeEventListener('mouseup', nodeMouseUp);
|
||||
|
||||
if (!_hoverStack.length) {
|
||||
_node = null;
|
||||
}
|
||||
};
|
||||
|
||||
function nodeMouseOver(event) {
|
||||
// Don't treat the node if it is already registered
|
||||
if (_hoverIndex[event.data.node.id]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add node to array of current nodes over
|
||||
_hoverStack.push(event.data.node);
|
||||
_hoverIndex[event.data.node.id] = true;
|
||||
|
||||
if(_hoverStack.length && ! _isMouseDown) {
|
||||
// Set the current node to be the last one in the array
|
||||
_node = _hoverStack[_hoverStack.length - 1];
|
||||
_mouse.addEventListener('mousedown', nodeMouseDown);
|
||||
}
|
||||
};
|
||||
|
||||
function treatOutNode(event) {
|
||||
// Remove the node from the array
|
||||
var indexCheck = _hoverStack.map(function(e) { return e; }).indexOf(event.data.node);
|
||||
_hoverStack.splice(indexCheck, 1);
|
||||
delete _hoverIndex[event.data.node.id];
|
||||
|
||||
if(_hoverStack.length && ! _isMouseDown) {
|
||||
// On out, set the current node to be the next stated in array
|
||||
_node = _hoverStack[_hoverStack.length - 1];
|
||||
} else {
|
||||
_mouse.removeEventListener('mousedown', nodeMouseDown);
|
||||
}
|
||||
};
|
||||
|
||||
function nodeMouseDown(event) {
|
||||
_isMouseDown = true;
|
||||
var size = _s.graph.nodes().length;
|
||||
|
||||
// when there is only node in the graph, the plugin cannot apply
|
||||
// linear interpolation. So treat it as if a user is dragging
|
||||
// the graph
|
||||
if (_node && size > 1) {
|
||||
_mouse.removeEventListener('mousedown', nodeMouseDown);
|
||||
_body.addEventListener('mousemove', nodeMouseMove);
|
||||
_body.addEventListener('mouseup', nodeMouseUp);
|
||||
|
||||
// Do not refresh edgequadtree during drag:
|
||||
var k,
|
||||
c;
|
||||
for (k in _s.cameras) {
|
||||
c = _s.cameras[k];
|
||||
if (c.edgequadtree !== undefined) {
|
||||
c.edgequadtree._enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Deactivate drag graph.
|
||||
_renderer.settings({mouseEnabled: false, enableHovering: false});
|
||||
_s.refresh();
|
||||
|
||||
_self.dispatchEvent('startdrag', {
|
||||
node: _node,
|
||||
captor: event,
|
||||
renderer: _renderer
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function nodeMouseUp(event) {
|
||||
_isMouseDown = false;
|
||||
_mouse.addEventListener('mousedown', nodeMouseDown);
|
||||
_body.removeEventListener('mousemove', nodeMouseMove);
|
||||
_body.removeEventListener('mouseup', nodeMouseUp);
|
||||
|
||||
// Allow to refresh edgequadtree:
|
||||
var k,
|
||||
c;
|
||||
for (k in _s.cameras) {
|
||||
c = _s.cameras[k];
|
||||
if (c.edgequadtree !== undefined) {
|
||||
c.edgequadtree._enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Activate drag graph.
|
||||
_renderer.settings({mouseEnabled: true, enableHovering: true});
|
||||
_s.refresh();
|
||||
|
||||
if (_drag) {
|
||||
_self.dispatchEvent('drop', {
|
||||
node: _node,
|
||||
captor: event,
|
||||
renderer: _renderer
|
||||
});
|
||||
}
|
||||
_self.dispatchEvent('dragend', {
|
||||
node: _node,
|
||||
captor: event,
|
||||
renderer: _renderer
|
||||
});
|
||||
|
||||
_drag = false;
|
||||
_node = null;
|
||||
};
|
||||
|
||||
function nodeMouseMove(event) {
|
||||
if(navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
|
||||
clearTimeout(timeOut);
|
||||
var timeOut = setTimeout(executeNodeMouseMove, 0);
|
||||
} else {
|
||||
executeNodeMouseMove();
|
||||
}
|
||||
|
||||
function executeNodeMouseMove() {
|
||||
var offset = calculateOffset(_renderer.container),
|
||||
x = event.clientX - offset.left,
|
||||
y = event.clientY - offset.top,
|
||||
cos = Math.cos(_camera.angle),
|
||||
sin = Math.sin(_camera.angle),
|
||||
nodes = _s.graph.nodes(),
|
||||
ref = [];
|
||||
|
||||
// Getting and derotating the reference coordinates.
|
||||
for (var i = 0; i < 2; i++) {
|
||||
var n = nodes[i];
|
||||
var aux = {
|
||||
x: n.x * cos + n.y * sin,
|
||||
y: n.y * cos - n.x * sin,
|
||||
renX: n[_prefix + 'x'],
|
||||
renY: n[_prefix + 'y'],
|
||||
};
|
||||
ref.push(aux);
|
||||
}
|
||||
|
||||
// Applying linear interpolation.
|
||||
// if the nodes are on top of each other, we use the camera ratio to interpolate
|
||||
if (ref[0].x === ref[1].x && ref[0].y === ref[1].y) {
|
||||
var xRatio = (ref[0].renX === 0) ? 1 : ref[0].renX;
|
||||
var yRatio = (ref[0].renY === 0) ? 1 : ref[0].renY;
|
||||
x = (ref[0].x / xRatio) * (x - ref[0].renX) + ref[0].x;
|
||||
y = (ref[0].y / yRatio) * (y - ref[0].renY) + ref[0].y;
|
||||
} else {
|
||||
var xRatio = (ref[1].renX - ref[0].renX) / (ref[1].x - ref[0].x);
|
||||
var yRatio = (ref[1].renY - ref[0].renY) / (ref[1].y - ref[0].y);
|
||||
|
||||
// if the coordinates are the same, we use the other ratio to interpolate
|
||||
if (ref[1].x === ref[0].x) {
|
||||
xRatio = yRatio;
|
||||
}
|
||||
|
||||
if (ref[1].y === ref[0].y) {
|
||||
yRatio = xRatio;
|
||||
}
|
||||
|
||||
x = (x - ref[0].renX) / xRatio + ref[0].x;
|
||||
y = (y - ref[0].renY) / yRatio + ref[0].y;
|
||||
}
|
||||
|
||||
// Rotating the coordinates.
|
||||
_node.x = x * cos - y * sin;
|
||||
_node.y = y * cos + x * sin;
|
||||
|
||||
_s.refresh();
|
||||
|
||||
_drag = true;
|
||||
_self.dispatchEvent('drag', {
|
||||
node: _node,
|
||||
captor: event,
|
||||
renderer: _renderer
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface
|
||||
* ------------------
|
||||
*
|
||||
* > var dragNodesListener = sigma.plugins.dragNodes(s, s.renderers[0]);
|
||||
*/
|
||||
var _instance = {};
|
||||
|
||||
/**
|
||||
* @param {sigma} s The related sigma instance.
|
||||
* @param {renderer} renderer The related renderer instance.
|
||||
*/
|
||||
sigma.plugins.dragNodes = function(s, renderer) {
|
||||
// Create object if undefined
|
||||
if (!_instance[s.id]) {
|
||||
_instance[s.id] = new DragNodes(s, renderer);
|
||||
}
|
||||
|
||||
s.bind('kill', function() {
|
||||
sigma.plugins.killDragNodes(s);
|
||||
});
|
||||
|
||||
return _instance[s.id];
|
||||
};
|
||||
|
||||
/**
|
||||
* This method removes the event listeners and kills the dragNodes instance.
|
||||
*
|
||||
* @param {sigma} s The related sigma instance.
|
||||
*/
|
||||
sigma.plugins.killDragNodes = function(s) {
|
||||
if (_instance[s.id] instanceof DragNodes) {
|
||||
_instance[s.id].unbindAll();
|
||||
delete _instance[s.id];
|
||||
}
|
||||
};
|
||||
|
||||
}).call(window);
|
|
@ -0,0 +1,187 @@
|
|||
sigma.plugins.filter
|
||||
==================
|
||||
|
||||
Plugin developed by [Sébastien Heymann](sheymann) for [Linkurious](https://github.com/Linkurious).
|
||||
|
||||
---
|
||||
## General
|
||||
This plugin filters nodes and edges in a fancy manner:
|
||||
- Define your own filters on nodes and edges using the `nodesBy` and `edgesBy` methods, or execute more complex filters using the `neighborsOf` method.
|
||||
- Register multiple filters before applying them anytime at once.
|
||||
- Undo any filter while preserving the execution order.
|
||||
- Chain all methods for concise style.
|
||||
|
||||
See the following [example code](../../examples/filters.html) and [unit tests](../../test/unit.plugins.filter.js) for full usage.
|
||||
|
||||
To use, include all .js files under this folder. Then initialize it as follows:
|
||||
|
||||
````javascript
|
||||
var filter = new sigma.plugins.filter(sigInst);
|
||||
````
|
||||
|
||||
## Predicates
|
||||
Predicates are truth tests (i.e. functions which return a boolean) on a single node or a single edge. They return true if the element should be visible. For instance:
|
||||
|
||||
````javascript
|
||||
// Only edges of size above one should be visible:
|
||||
function(e) {
|
||||
return e.size > 1;
|
||||
}
|
||||
````
|
||||
|
||||
In this example, notice that if the size attribute is undefined, the edge will be hidden. If you still want to display edges with no size attribute defined, you have to modify the predicate a bit:
|
||||
|
||||
````javascript
|
||||
// Only edges of size above one should be visible:
|
||||
function(e) {
|
||||
return e.size === undefined || e.size > 1;
|
||||
}
|
||||
````
|
||||
|
||||
Predicates are applied by predicate processors.
|
||||
|
||||
## Predicate processors
|
||||
Predicate processors are functions which wrap one predicate and apply it to the graph. Three predicate processors are available:
|
||||
- `nodesBy`
|
||||
- `edgesBy`
|
||||
- `neighborsOf`
|
||||
|
||||
For each node of the graph, the `nodesBy` processor sets the attribute `hidden` to false if the predicate is true for the node. It also sets the `hidden` attribute of edges to true if one of the edge's extremities is hidden. For instance:
|
||||
|
||||
````javascript
|
||||
// Only connected nodes (i.e. nodes of positive degree) should be visible:
|
||||
filter.nodesBy(function(n) {
|
||||
return this.degree(n.id) > 0;
|
||||
}, 'non-isolates');
|
||||
````
|
||||
|
||||
For each edge of the graph, the `edgesBy` processor sets the attribute `hidden` to false if the predicate is true for the edge. For instance:
|
||||
|
||||
````javascript
|
||||
// Only edges of size above one should be visible:
|
||||
filter.edgesBy(function(e) {
|
||||
return e.size > 1;
|
||||
}, 'edge-size-above-one');
|
||||
````
|
||||
|
||||
For each neighbor node of a specified node, the `neighborsOf` processor sets the attribute `hidden` to true if it is not directly connected to the node. It also sets the `hidden` attribute of edges to true if one of the edge's extremities is hidden. For instance:
|
||||
|
||||
````javascript
|
||||
// Only neighbors of the node 'n0' should be visible:
|
||||
filter.neighborsOf('n0');
|
||||
````
|
||||
|
||||
Processors instanciated with a predicate are called filters. **Filters are not applied until the `apply` method is called.**
|
||||
|
||||
## Filters chain
|
||||
Combining filters is easy! Declare one filter after another, then call the `apply` method to execute them on the graph in that order. For instance:
|
||||
|
||||
````javascript
|
||||
// graph = {
|
||||
// nodes: [{id:'n0'}, {id:'n1'}, {id:'n2'}, {id:'n3'}],
|
||||
// edges: [
|
||||
// {id:'e0', source:'n0', target:'n1', size:1},
|
||||
// {id:'e1', source:'n1', target:'n2', size:0.5},
|
||||
// {id:'e2', source:'n1', target:'n2'}]
|
||||
// }
|
||||
filter
|
||||
.nodesBy(function(n) {
|
||||
return this.degree(n.id) > 0;
|
||||
})
|
||||
.edgesBy(function(e) {
|
||||
return e.size >= 1;
|
||||
})
|
||||
.apply();
|
||||
// n3.hidden == true
|
||||
// e1.hidden == true
|
||||
// e2.hidden == true
|
||||
````
|
||||
|
||||
Combined filters work like if there was an 'AND' operator between them. Be careful not to create mutually exclusive filters, for instance:
|
||||
|
||||
````javascript
|
||||
filter
|
||||
.nodesBy(function(n) {
|
||||
return n.attributes.animal === 'pony';
|
||||
})
|
||||
.nodesBy(function(n) {
|
||||
return n.attributes.animal !== 'pony';
|
||||
})
|
||||
.apply();
|
||||
// all nodes are hidden
|
||||
````
|
||||
|
||||
Filters are internally stored in an array called the `chain`.
|
||||
|
||||
## Undo filters
|
||||
Undoing filters means to remove them from the `chain`. Filters can be undone easily. Choose which filter(s) to undo, or undo all of them at once.
|
||||
|
||||
Filters can be associated with keys at declaration, where keys are any string you give. For instance, the following filter has the key *node-animal*:
|
||||
|
||||
````javascript
|
||||
filter.nodesBy(function(n) {
|
||||
return n.attributes.animal === 'pony';
|
||||
}, 'node-animal');
|
||||
````
|
||||
|
||||
Manually undo this filter as follows:
|
||||
|
||||
````javascript
|
||||
filter
|
||||
.undo('node-animal')
|
||||
.apply(); // we want it applied now
|
||||
````
|
||||
|
||||
Multiple filters can be undone at once, for instance:
|
||||
|
||||
````javascript
|
||||
filter.undo('node-animal', 'edge-size', 'high-node-degree');
|
||||
// don't forget to call `apply()` anytime!
|
||||
````
|
||||
|
||||
Alternative syntax:
|
||||
|
||||
````javascript
|
||||
var a = ['node-animal', 'edge-size', 'high-node-degree'];
|
||||
filter.undo(a);
|
||||
// don't forget to call `apply()` anytime!
|
||||
````
|
||||
|
||||
Finally, undo all filters (with or without keys) as follows:
|
||||
|
||||
````javascript
|
||||
filter.undo();
|
||||
// don't forget to call `apply()` anytime!
|
||||
````
|
||||
|
||||
Warning: you can't declare two filters with the same key, or it will throw an exception.
|
||||
|
||||
## Export the chain
|
||||
The exported chain is an array of objects. Each object represents a filter by a triplet *(?key, processor, predicate)*. The processor value is the internal name of the processor: `filter.processors.nodes`, `filter.processors.edges`, `filter.processors.neighbors`. The predicate value is a copy of the predicate function. Dump the `chain` using the `export` method as follows:
|
||||
|
||||
````javascript
|
||||
var chain = filter.export();
|
||||
// chain == [
|
||||
// {
|
||||
// key: '...',
|
||||
// processor: '...',
|
||||
// predicate: function() {...}
|
||||
// }, ...
|
||||
// ]
|
||||
````
|
||||
|
||||
## Import a chain
|
||||
You can load a filters chain using the `import` method:
|
||||
|
||||
````javascript
|
||||
var chain = [
|
||||
{
|
||||
key: 'my-filter',
|
||||
predicate: function(n) { return this.degree(n.id) > 0; },
|
||||
processor: 'filter.processors.nodes'
|
||||
}
|
||||
];
|
||||
filter
|
||||
.import(chain)
|
||||
.apply();
|
||||
````
|
|
@ -0,0 +1,504 @@
|
|||
;(function(undefined) {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined')
|
||||
throw 'sigma is not declared';
|
||||
|
||||
// Initialize package:
|
||||
sigma.utils.pkg('sigma.plugins');
|
||||
|
||||
// Add custom graph methods:
|
||||
/**
|
||||
* This methods returns an array of nodes that are adjacent to a node.
|
||||
*
|
||||
* @param {string} id The node id.
|
||||
* @return {array} The array of adjacent nodes.
|
||||
*/
|
||||
if (!sigma.classes.graph.hasMethod('adjacentNodes'))
|
||||
sigma.classes.graph.addMethod('adjacentNodes', function(id) {
|
||||
if (typeof id !== 'string')
|
||||
throw 'adjacentNodes: the node id must be a string.';
|
||||
|
||||
var target,
|
||||
nodes = [];
|
||||
for(target in this.allNeighborsIndex[id]) {
|
||||
nodes.push(this.nodesIndex[target]);
|
||||
}
|
||||
return nodes;
|
||||
});
|
||||
|
||||
/**
|
||||
* This methods returns an array of edges that are adjacent to a node.
|
||||
*
|
||||
* @param {string} id The node id.
|
||||
* @return {array} The array of adjacent edges.
|
||||
*/
|
||||
if (!sigma.classes.graph.hasMethod('adjacentEdges'))
|
||||
sigma.classes.graph.addMethod('adjacentEdges', function(id) {
|
||||
if (typeof id !== 'string')
|
||||
throw 'adjacentEdges: the node id must be a string.';
|
||||
|
||||
var a = this.allNeighborsIndex[id],
|
||||
eid,
|
||||
target,
|
||||
edges = [];
|
||||
for(target in a) {
|
||||
for(eid in a[target]) {
|
||||
edges.push(a[target][eid]);
|
||||
}
|
||||
}
|
||||
return edges;
|
||||
});
|
||||
|
||||
/**
|
||||
* Sigma Filter
|
||||
* =============================
|
||||
*
|
||||
* @author Sébastien Heymann <seb@linkurio.us> (Linkurious)
|
||||
* @version 0.1
|
||||
*/
|
||||
|
||||
var _g = undefined,
|
||||
_s = undefined,
|
||||
_chain = [], // chain of wrapped filters
|
||||
_keysIndex = Object.create(null),
|
||||
Processors = {}; // available predicate processors
|
||||
|
||||
|
||||
/**
|
||||
* Library of processors
|
||||
* ------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {function} fn The predicate.
|
||||
*/
|
||||
Processors.nodes = function nodes(fn) {
|
||||
var n = _g.nodes(),
|
||||
ln = n.length,
|
||||
e = _g.edges(),
|
||||
le = e.length;
|
||||
|
||||
// hide node, or keep former value
|
||||
while(ln--)
|
||||
n[ln].hidden = !fn.call(_g, n[ln]) || n[ln].hidden;
|
||||
|
||||
while(le--)
|
||||
if (_g.nodes(e[le].source).hidden || _g.nodes(e[le].target).hidden)
|
||||
e[le].hidden = true;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {function} fn The predicate.
|
||||
*/
|
||||
Processors.edges = function edges(fn) {
|
||||
var e = _g.edges(),
|
||||
le = e.length;
|
||||
|
||||
// hide edge, or keep former value
|
||||
while(le--)
|
||||
e[le].hidden = !fn.call(_g, e[le]) || e[le].hidden;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} id The center node.
|
||||
*/
|
||||
Processors.neighbors = function neighbors(id) {
|
||||
var n = _g.nodes(),
|
||||
ln = n.length,
|
||||
e = _g.edges(),
|
||||
le = e.length,
|
||||
neighbors = _g.adjacentNodes(id),
|
||||
nn = neighbors.length,
|
||||
no = {};
|
||||
|
||||
while(nn--)
|
||||
no[neighbors[nn].id] = true;
|
||||
|
||||
while(ln--)
|
||||
if (n[ln].id !== id && !(n[ln].id in no))
|
||||
n[ln].hidden = true;
|
||||
|
||||
while(le--)
|
||||
if (_g.nodes(e[le].source).hidden || _g.nodes(e[le].target).hidden)
|
||||
e[le].hidden = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This function adds a filter to the chain of filters.
|
||||
*
|
||||
* @param {function} fn The filter (i.e. predicate processor).
|
||||
* @param {function} p The predicate.
|
||||
* @param {?string} key The key to identify the filter.
|
||||
*/
|
||||
function register(fn, p, key) {
|
||||
if (key != undefined && typeof key !== 'string')
|
||||
throw 'The filter key "'+ key.toString() +'" must be a string.';
|
||||
|
||||
if (key != undefined && !key.length)
|
||||
throw 'The filter key must be a non-empty string.';
|
||||
|
||||
if (typeof fn !== 'function')
|
||||
throw 'The predicate of key "'+ key +'" must be a function.';
|
||||
|
||||
if ('undo' === key)
|
||||
throw '"undo" is a reserved key.';
|
||||
|
||||
if (_keysIndex[key])
|
||||
throw 'The filter "' + key + '" already exists.';
|
||||
|
||||
if (key)
|
||||
_keysIndex[key] = true;
|
||||
|
||||
_chain.push({
|
||||
'key': key,
|
||||
'processor': fn,
|
||||
'predicate': p
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* This function removes a set of filters from the chain.
|
||||
*
|
||||
* @param {object} o The filter keys.
|
||||
*/
|
||||
function unregister (o) {
|
||||
_chain = _chain.filter(function(a) {
|
||||
return !(a.key in o);
|
||||
});
|
||||
|
||||
for(var key in o)
|
||||
delete _keysIndex[key];
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Filter Object
|
||||
* ------------------
|
||||
* @param {sigma} s The related sigma instance.
|
||||
*/
|
||||
function Filter(s) {
|
||||
_s = s;
|
||||
_g = s.graph;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This method is used to filter the nodes. The method must be called with
|
||||
* the predicate, which is a function that takes a node as argument and
|
||||
* returns a boolean. It may take an identifier as argument to undo the
|
||||
* filter later. The method wraps the predicate into an anonymous function
|
||||
* that looks through each node in the graph. When executed, the anonymous
|
||||
* function hides the nodes that fail a truth test (predicate). The method
|
||||
* adds the anonymous function to the chain of filters. The filter is not
|
||||
* executed until the apply() method is called.
|
||||
*
|
||||
* > var filter = new sigma.plugins.filter(s);
|
||||
* > filter.nodesBy(function(n) {
|
||||
* > return this.degree(n.id) > 0;
|
||||
* > }, 'degreeNotNull');
|
||||
*
|
||||
* @param {function} fn The filter predicate.
|
||||
* @param {?string} key The key to identify the filter.
|
||||
* @return {sigma.plugins.filter} Returns the instance.
|
||||
*/
|
||||
Filter.prototype.nodesBy = function(fn, key) {
|
||||
// Wrap the predicate to be applied on the graph and add it to the chain.
|
||||
register(Processors.nodes, fn, key);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* This method is used to filter the edges. The method must be called with
|
||||
* the predicate, which is a function that takes a node as argument and
|
||||
* returns a boolean. It may take an identifier as argument to undo the
|
||||
* filter later. The method wraps the predicate into an anonymous function
|
||||
* that looks through each edge in the graph. When executed, the anonymous
|
||||
* function hides the edges that fail a truth test (predicate). The method
|
||||
* adds the anonymous function to the chain of filters. The filter is not
|
||||
* executed until the apply() method is called.
|
||||
*
|
||||
* > var filter = new sigma.plugins.filter(s);
|
||||
* > filter.edgesBy(function(e) {
|
||||
* > return e.size > 1;
|
||||
* > }, 'edgeSize');
|
||||
*
|
||||
* @param {function} fn The filter predicate.
|
||||
* @param {?string} key The key to identify the filter.
|
||||
* @return {sigma.plugins.filter} Returns the instance.
|
||||
*/
|
||||
Filter.prototype.edgesBy = function(fn, key) {
|
||||
// Wrap the predicate to be applied on the graph and add it to the chain.
|
||||
register(Processors.edges, fn, key);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* This method is used to filter the nodes which are not direct connections
|
||||
* of a given node. The method must be called with the node identifier. It
|
||||
* may take an identifier as argument to undo the filter later. The filter
|
||||
* is not executed until the apply() method is called.
|
||||
*
|
||||
* > var filter = new sigma.plugins.filter(s);
|
||||
* > filter.neighborsOf('n0');
|
||||
*
|
||||
* @param {string} id The node id.
|
||||
* @param {?string} key The key to identify the filter.
|
||||
* @return {sigma.plugins.filter} Returns the instance.
|
||||
*/
|
||||
Filter.prototype.neighborsOf = function(id, key) {
|
||||
if (typeof id !== 'string')
|
||||
throw 'The node id "'+ id.toString() +'" must be a string.';
|
||||
if (!id.length)
|
||||
throw 'The node id must be a non-empty string.';
|
||||
|
||||
// Wrap the predicate to be applied on the graph and add it to the chain.
|
||||
register(Processors.neighbors, id, key);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* This method is used to execute the chain of filters and to refresh the
|
||||
* display.
|
||||
*
|
||||
* > var filter = new sigma.plugins.filter(s);
|
||||
* > filter
|
||||
* > .nodesBy(function(n) {
|
||||
* > return this.degree(n.id) > 0;
|
||||
* > }, 'degreeNotNull')
|
||||
* > .apply();
|
||||
*
|
||||
* @return {sigma.plugins.filter} Returns the instance.
|
||||
*/
|
||||
Filter.prototype.apply = function() {
|
||||
for (var i = 0, len = _chain.length; i < len; ++i) {
|
||||
_chain[i].processor(_chain[i].predicate);
|
||||
};
|
||||
|
||||
if (_chain[0] && 'undo' === _chain[0].key) {
|
||||
_chain.shift();
|
||||
}
|
||||
|
||||
_s.refresh();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* This method undoes one or several filters, depending on how it is called.
|
||||
*
|
||||
* To undo all filters, call "undo" without argument. To undo a specific
|
||||
* filter, call it with the key of the filter. To undo multiple filters, call
|
||||
* it with an array of keys or multiple arguments, and it will undo each
|
||||
* filter, in the same order. The undo is not executed until the apply()
|
||||
* method is called. For instance:
|
||||
*
|
||||
* > var filter = new sigma.plugins.filter(s);
|
||||
* > filter
|
||||
* > .nodesBy(function(n) {
|
||||
* > return this.degree(n.id) > 0;
|
||||
* > }, 'degreeNotNull');
|
||||
* > .edgesBy(function(e) {
|
||||
* > return e.size > 1;
|
||||
* > }, 'edgeSize')
|
||||
* > .undo();
|
||||
*
|
||||
* Other examples:
|
||||
* > filter.undo();
|
||||
* > filter.undo('myfilter');
|
||||
* > filter.undo(['myfilter1', 'myfilter2']);
|
||||
* > filter.undo('myfilter1', 'myfilter2');
|
||||
*
|
||||
* @param {?(string|array|*string))} v Eventually one key, an array of keys.
|
||||
* @return {sigma.plugins.filter} Returns the instance.
|
||||
*/
|
||||
Filter.prototype.undo = function(v) {
|
||||
var q = Object.create(null),
|
||||
la = arguments.length;
|
||||
|
||||
// find removable filters
|
||||
if (la === 1) {
|
||||
if (Object.prototype.toString.call(v) === '[object Array]')
|
||||
for (var i = 0, len = v.length; i < len; i++)
|
||||
q[v[i]] = true;
|
||||
|
||||
else // 1 filter key
|
||||
q[v] = true;
|
||||
|
||||
} else if (la > 1) {
|
||||
for (var i = 0; i < la; i++)
|
||||
q[arguments[i]] = true;
|
||||
}
|
||||
else
|
||||
this.clear();
|
||||
|
||||
unregister(q);
|
||||
|
||||
function processor() {
|
||||
var n = _g.nodes(),
|
||||
ln = n.length,
|
||||
e = _g.edges(),
|
||||
le = e.length;
|
||||
|
||||
while(ln--)
|
||||
n[ln].hidden = false;
|
||||
|
||||
while(le--)
|
||||
e[le].hidden = false;
|
||||
};
|
||||
|
||||
_chain.unshift({
|
||||
'key': 'undo',
|
||||
'processor': processor
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// fast deep copy function
|
||||
function deepCopy(o) {
|
||||
var copy = Object.create(null);
|
||||
for (var i in o) {
|
||||
if (typeof o[i] === "object" && o[i] !== null) {
|
||||
copy[i] = deepCopy(o[i]);
|
||||
}
|
||||
else if (typeof o[i] === "function" && o[i] !== null) {
|
||||
// clone function:
|
||||
eval(" copy[i] = " + o[i].toString());
|
||||
//copy[i] = o[i].bind(_g);
|
||||
}
|
||||
|
||||
else
|
||||
copy[i] = o[i];
|
||||
}
|
||||
return copy;
|
||||
};
|
||||
|
||||
function cloneChain(chain) {
|
||||
// Clone the array of filters:
|
||||
var copy = chain.slice(0);
|
||||
for (var i = 0, len = copy.length; i < len; i++) {
|
||||
copy[i] = deepCopy(copy[i]);
|
||||
if (typeof copy[i].processor === "function")
|
||||
copy[i].processor = 'filter.processors.' + copy[i].processor.name;
|
||||
};
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to empty the chain of filters.
|
||||
* Prefer the undo() method to reset filters.
|
||||
*
|
||||
* > var filter = new sigma.plugins.filter(s);
|
||||
* > filter.clear();
|
||||
*
|
||||
* @return {sigma.plugins.filter} Returns the instance.
|
||||
*/
|
||||
Filter.prototype.clear = function() {
|
||||
_chain.length = 0; // clear the array
|
||||
_keysIndex = Object.create(null);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* This method clones the filter chain and return the copy.
|
||||
*
|
||||
* > var filter = new sigma.plugins.filter(s);
|
||||
* > var chain = filter.export();
|
||||
*
|
||||
* @return {object} The cloned chain of filters.
|
||||
*/
|
||||
Filter.prototype.export = function() {
|
||||
var c = cloneChain(_chain);
|
||||
return c;
|
||||
};
|
||||
|
||||
/**
|
||||
* This method sets the chain of filters with the specified chain.
|
||||
*
|
||||
* > var filter = new sigma.plugins.filter(s);
|
||||
* > var chain = [
|
||||
* > {
|
||||
* > key: 'my-filter',
|
||||
* > predicate: function(n) {...},
|
||||
* > processor: 'filter.processors.nodes'
|
||||
* > }, ...
|
||||
* > ];
|
||||
* > filter.import(chain);
|
||||
*
|
||||
* @param {array} chain The chain of filters.
|
||||
* @return {sigma.plugins.filter} Returns the instance.
|
||||
*/
|
||||
Filter.prototype.import = function(chain) {
|
||||
if (chain === undefined)
|
||||
throw 'Wrong arguments.';
|
||||
|
||||
if (Object.prototype.toString.call(chain) !== '[object Array]')
|
||||
throw 'The chain" must be an array.';
|
||||
|
||||
var copy = cloneChain(chain);
|
||||
|
||||
for (var i = 0, len = copy.length; i < len; i++) {
|
||||
if (copy[i].predicate === undefined || copy[i].processor === undefined)
|
||||
throw 'Wrong arguments.';
|
||||
|
||||
if (copy[i].key != undefined && typeof copy[i].key !== 'string')
|
||||
throw 'The filter key "'+ copy[i].key.toString() +'" must be a string.';
|
||||
|
||||
if (typeof copy[i].predicate !== 'function')
|
||||
throw 'The predicate of key "'+ copy[i].key +'" must be a function.';
|
||||
|
||||
if (typeof copy[i].processor !== 'string')
|
||||
throw 'The processor of key "'+ copy[i].key +'" must be a string.';
|
||||
|
||||
// Replace the processor name by the corresponding function:
|
||||
switch(copy[i].processor) {
|
||||
case 'filter.processors.nodes':
|
||||
copy[i].processor = Processors.nodes;
|
||||
break;
|
||||
case 'filter.processors.edges':
|
||||
copy[i].processor = Processors.edges;
|
||||
break;
|
||||
case 'filter.processors.neighbors':
|
||||
copy[i].processor = Processors.neighbors;
|
||||
break;
|
||||
default:
|
||||
throw 'Unknown processor ' + copy[i].processor;
|
||||
}
|
||||
};
|
||||
|
||||
_chain = copy;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Interface
|
||||
* ------------------
|
||||
*
|
||||
* > var filter = new sigma.plugins.filter(s);
|
||||
*/
|
||||
var filter = null;
|
||||
|
||||
/**
|
||||
* @param {sigma} s The related sigma instance.
|
||||
*/
|
||||
sigma.plugins.filter = function(s) {
|
||||
// Create filter if undefined
|
||||
if (!filter) {
|
||||
filter = new Filter(s);
|
||||
}
|
||||
return filter;
|
||||
};
|
||||
|
||||
}).call(this);
|
|
@ -0,0 +1,24 @@
|
|||
sigma.plugins.neighborhood
|
||||
==========================
|
||||
|
||||
Plugin developed by [Alexis Jacomy](https://github.com/jacomyal).
|
||||
|
||||
---
|
||||
|
||||
This plugin provides a method to retrieve the neighborhood of a node. Basically, it loads a graph and stores it in a headless `sigma.classes.graph` instance, that you can query to retrieve neighborhoods.
|
||||
|
||||
It is useful for people who want to provide a neighborhoods navigation inside a big graph instead of just displaying it, and without having to deploy an API or the list of every neighborhoods. But please note that this plugin is here as an example of what you can do with the graph model, and do not hesitate to try customizing your navigation through graphs.
|
||||
|
||||
This plugin also adds to the graph model a method called "neighborhood". Check the code for more information.
|
||||
|
||||
Here is how to use it:
|
||||
|
||||
````javascript
|
||||
var db = new sigma.plugins.neighborhoods();
|
||||
db.load('path/to/my/graph.json', function() {
|
||||
var nodeId = 'anyNodeID';
|
||||
mySigmaInstance
|
||||
.read(db.neighborhood(nodeId))
|
||||
.refresh();
|
||||
});
|
||||
````
|
|
@ -0,0 +1,186 @@
|
|||
/**
|
||||
* This plugin provides a method to retrieve the neighborhood of a node.
|
||||
* Basically, it loads a graph and stores it in a headless sigma.classes.graph
|
||||
* instance, that you can query to retrieve neighborhoods.
|
||||
*
|
||||
* It is useful for people who want to provide a neighborhoods navigation
|
||||
* inside a big graph instead of just displaying it, and without having to
|
||||
* deploy an API or the list of every neighborhoods.
|
||||
*
|
||||
* This plugin also adds to the graph model a method called "neighborhood".
|
||||
* Check the code for more information.
|
||||
*
|
||||
* Here is how to use it:
|
||||
*
|
||||
* > var db = new sigma.plugins.neighborhoods();
|
||||
* > db.load('path/to/my/graph.json', function() {
|
||||
* > var nodeId = 'anyNodeID';
|
||||
* > mySigmaInstance
|
||||
* > .read(db.neighborhood(nodeId))
|
||||
* > .refresh();
|
||||
* > });
|
||||
*/
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined')
|
||||
throw 'sigma is not declared';
|
||||
|
||||
/**
|
||||
* This method takes the ID of node as argument and returns the graph of the
|
||||
* specified node, with every other nodes that are connected to it and every
|
||||
* edges that connect two of the previously cited nodes. It uses the built-in
|
||||
* indexes from sigma's graph model to search in the graph.
|
||||
*
|
||||
* @param {string} centerId The ID of the center node.
|
||||
* @return {object} The graph, as a simple descriptive object, in
|
||||
* the format required by the "read" graph method.
|
||||
*/
|
||||
sigma.classes.graph.addMethod(
|
||||
'neighborhood',
|
||||
function(centerId) {
|
||||
var k1,
|
||||
k2,
|
||||
k3,
|
||||
node,
|
||||
center,
|
||||
// Those two local indexes are here just to avoid duplicates:
|
||||
localNodesIndex = {},
|
||||
localEdgesIndex = {},
|
||||
// And here is the resulted graph, empty at the moment:
|
||||
graph = {
|
||||
nodes: [],
|
||||
edges: []
|
||||
};
|
||||
|
||||
// Check that the exists:
|
||||
if (!this.nodes(centerId))
|
||||
return graph;
|
||||
|
||||
// Add center. It has to be cloned to add it the "center" attribute
|
||||
// without altering the current graph:
|
||||
node = this.nodes(centerId);
|
||||
center = {};
|
||||
center.center = true;
|
||||
for (k1 in node)
|
||||
center[k1] = node[k1];
|
||||
|
||||
localNodesIndex[centerId] = true;
|
||||
graph.nodes.push(center);
|
||||
|
||||
// Add neighbors and edges between the center and the neighbors:
|
||||
for (k1 in this.allNeighborsIndex[centerId]) {
|
||||
if (!localNodesIndex[k1]) {
|
||||
localNodesIndex[k1] = true;
|
||||
graph.nodes.push(this.nodesIndex[k1]);
|
||||
}
|
||||
|
||||
for (k2 in this.allNeighborsIndex[centerId][k1])
|
||||
if (!localEdgesIndex[k2]) {
|
||||
localEdgesIndex[k2] = true;
|
||||
graph.edges.push(this.edgesIndex[k2]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add edges connecting two neighbors:
|
||||
for (k1 in localNodesIndex)
|
||||
if (k1 !== centerId)
|
||||
for (k2 in localNodesIndex)
|
||||
if (
|
||||
k2 !== centerId &&
|
||||
k1 !== k2 &&
|
||||
this.allNeighborsIndex[k1][k2]
|
||||
)
|
||||
for (k3 in this.allNeighborsIndex[k1][k2])
|
||||
if (!localEdgesIndex[k3]) {
|
||||
localEdgesIndex[k3] = true;
|
||||
graph.edges.push(this.edgesIndex[k3]);
|
||||
}
|
||||
|
||||
// Finally, let's return the final graph:
|
||||
return graph;
|
||||
}
|
||||
);
|
||||
|
||||
sigma.utils.pkg('sigma.plugins');
|
||||
|
||||
/**
|
||||
* sigma.plugins.neighborhoods constructor.
|
||||
*/
|
||||
sigma.plugins.neighborhoods = function() {
|
||||
var ready = false,
|
||||
readyCallbacks = [],
|
||||
graph = new sigma.classes.graph();
|
||||
|
||||
/**
|
||||
* This method just returns the neighborhood of a node.
|
||||
*
|
||||
* @param {string} centerNodeID The ID of the center node.
|
||||
* @return {object} Returns the neighborhood.
|
||||
*/
|
||||
this.neighborhood = function(centerNodeID) {
|
||||
return graph.neighborhood(centerNodeID);
|
||||
};
|
||||
|
||||
/**
|
||||
* This method loads the JSON graph at "path", stores it in the local graph
|
||||
* instance, and executes the callback.
|
||||
*
|
||||
* @param {string} path The path of the JSON graph file.
|
||||
* @param {?function} callback Eventually a callback to execute.
|
||||
*/
|
||||
this.load = function(path, callback) {
|
||||
// Quick XHR polyfill:
|
||||
var xhr = (function() {
|
||||
if (window.XMLHttpRequest)
|
||||
return new XMLHttpRequest();
|
||||
|
||||
var names,
|
||||
i;
|
||||
|
||||
if (window.ActiveXObject) {
|
||||
names = [
|
||||
'Msxml2.XMLHTTP.6.0',
|
||||
'Msxml2.XMLHTTP.3.0',
|
||||
'Msxml2.XMLHTTP',
|
||||
'Microsoft.XMLHTTP'
|
||||
];
|
||||
|
||||
for (i in names)
|
||||
try {
|
||||
return new ActiveXObject(names[i]);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
return null;
|
||||
})();
|
||||
|
||||
if (!xhr)
|
||||
throw 'XMLHttpRequest not supported, cannot load the data.';
|
||||
|
||||
xhr.open('GET', path, true);
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === 4) {
|
||||
graph.clear().read(JSON.parse(xhr.responseText));
|
||||
|
||||
if (callback)
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
// Start loading the file:
|
||||
xhr.send();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* This method cleans the graph instance "reads" a graph into it.
|
||||
*
|
||||
* @param {object} g The graph object to read.
|
||||
*/
|
||||
this.read = function(g) {
|
||||
graph.clear().read(g);
|
||||
};
|
||||
};
|
||||
}).call(window);
|
|
@ -0,0 +1,8 @@
|
|||
sigma.plugins.relativeSize
|
||||
=====================
|
||||
|
||||
Plugin developed by [Anatoliy Stegniy](https://github.com/tsdaemon).
|
||||
|
||||
---
|
||||
|
||||
This plugin provides a method to change nodes size depending to their degree (number of relationships)
|
|
@ -0,0 +1,28 @@
|
|||
(function() {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined')
|
||||
throw 'sigma is not declared';
|
||||
|
||||
sigma.utils.pkg('sigma.plugins');
|
||||
|
||||
var _id = 0,
|
||||
_cache = {};
|
||||
|
||||
/**
|
||||
* This function will change size for all nodes depending to their degree
|
||||
*
|
||||
* @param {sigma} s The related sigma instance.
|
||||
* @param {object} initialSize Start size property
|
||||
*/
|
||||
sigma.plugins.relativeSize = function(s, initialSize) {
|
||||
var nodes = s.graph.nodes();
|
||||
|
||||
// second create size for every node
|
||||
for(var i = 0; i < nodes.length; i++) {
|
||||
var degree = s.graph.degree(nodes[i].id);
|
||||
nodes[i].size = initialSize * Math.sqrt(degree);
|
||||
}
|
||||
s.refresh();
|
||||
};
|
||||
}).call(window);
|
|
@ -0,0 +1,21 @@
|
|||
sigma.renderers.customEdgeShapes
|
||||
==================
|
||||
|
||||
Plugin developed by [Sébastien Heymann](https://github.com/sheymann) for [Linkurious](https://github.com/Linkurious).
|
||||
|
||||
Contact: seb@linkurio.us
|
||||
|
||||
---
|
||||
## General
|
||||
This plugin registers custom edge shape renderers. See the following [example code](../../examples/plugin-customEdgeShapes.html) for full usage.
|
||||
|
||||
To use, include all .js files under this folder.
|
||||
|
||||
## Shapes
|
||||
The plugin implements the following shapes:
|
||||
* `dashed`
|
||||
* `dotted`
|
||||
* `parallel`: two solid parallel lines representing an edge aggregating multiple edges in the original graph.
|
||||
* `tapered` (see Danny Holten, Petra Isenberg, Jean-Daniel Fekete, and J. Van Wijk (2010) Performance Evaluation of Tapered, Curved, and Animated Directed-Edge Representations in Node-Link Graphs. Research Report, Sep 2010.)
|
||||
|
||||
To assign a shape renderer to an edge, simply set `edge.type='shape-name'` e.g. `edge.type='dotted'`. The default renderer implemented by sigma.js is named `def` (alias `line`) - see also [generic custom edge renderer example](../../examples/custom-edge-renderer.html).
|
|
@ -0,0 +1,64 @@
|
|||
;(function() {
|
||||
'use strict';
|
||||
|
||||
sigma.utils.pkg('sigma.canvas.edgehovers');
|
||||
|
||||
/**
|
||||
* This hover renderer will display the edge with a different color or size.
|
||||
*
|
||||
* @param {object} edge The edge object.
|
||||
* @param {object} source node The edge source node.
|
||||
* @param {object} target node The edge target node.
|
||||
* @param {CanvasRenderingContext2D} context The canvas context.
|
||||
* @param {configurable} settings The settings function.
|
||||
*/
|
||||
sigma.canvas.edgehovers.dashed =
|
||||
function(edge, source, target, context, settings) {
|
||||
var color = edge.active ?
|
||||
edge.active_color || settings('defaultEdgeActiveColor') :
|
||||
edge.color,
|
||||
prefix = settings('prefix') || '',
|
||||
size = edge[prefix + 'size'] || 1,
|
||||
edgeColor = settings('edgeColor'),
|
||||
defaultNodeColor = settings('defaultNodeColor'),
|
||||
defaultEdgeColor = settings('defaultEdgeColor');
|
||||
|
||||
if (!color)
|
||||
switch (edgeColor) {
|
||||
case 'source':
|
||||
color = source.color || defaultNodeColor;
|
||||
break;
|
||||
case 'target':
|
||||
color = target.color || defaultNodeColor;
|
||||
break;
|
||||
default:
|
||||
color = defaultEdgeColor;
|
||||
break;
|
||||
}
|
||||
|
||||
if (settings('edgeHoverColor') === 'edge') {
|
||||
color = edge.hover_color || color;
|
||||
} else {
|
||||
color = edge.hover_color || settings('defaultEdgeHoverColor') || color;
|
||||
}
|
||||
size *= settings('edgeHoverSizeRatio');
|
||||
|
||||
context.save();
|
||||
|
||||
context.setLineDash([8,3]);
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = size;
|
||||
context.beginPath();
|
||||
context.moveTo(
|
||||
source[prefix + 'x'],
|
||||
source[prefix + 'y']
|
||||
);
|
||||
context.lineTo(
|
||||
target[prefix + 'x'],
|
||||
target[prefix + 'y']
|
||||
);
|
||||
context.stroke();
|
||||
|
||||
context.restore();
|
||||
};
|
||||
})();
|
|
@ -0,0 +1,64 @@
|
|||
;(function() {
|
||||
'use strict';
|
||||
|
||||
sigma.utils.pkg('sigma.canvas.edgehovers');
|
||||
|
||||
/**
|
||||
* This hover renderer will display the edge with a different color or size.
|
||||
*
|
||||
* @param {object} edge The edge object.
|
||||
* @param {object} source node The edge source node.
|
||||
* @param {object} target node The edge target node.
|
||||
* @param {CanvasRenderingContext2D} context The canvas context.
|
||||
* @param {configurable} settings The settings function.
|
||||
*/
|
||||
sigma.canvas.edgehovers.dotted =
|
||||
function(edge, source, target, context, settings) {
|
||||
var color = edge.active ?
|
||||
edge.active_color || settings('defaultEdgeActiveColor') :
|
||||
edge.color,
|
||||
prefix = settings('prefix') || '',
|
||||
size = edge[prefix + 'size'] || 1,
|
||||
edgeColor = settings('edgeColor'),
|
||||
defaultNodeColor = settings('defaultNodeColor'),
|
||||
defaultEdgeColor = settings('defaultEdgeColor');
|
||||
|
||||
if (!color)
|
||||
switch (edgeColor) {
|
||||
case 'source':
|
||||
color = source.color || defaultNodeColor;
|
||||
break;
|
||||
case 'target':
|
||||
color = target.color || defaultNodeColor;
|
||||
break;
|
||||
default:
|
||||
color = defaultEdgeColor;
|
||||
break;
|
||||
}
|
||||
|
||||
if (settings('edgeHoverColor') === 'edge') {
|
||||
color = edge.hover_color || color;
|
||||
} else {
|
||||
color = edge.hover_color || settings('defaultEdgeHoverColor') || color;
|
||||
}
|
||||
size *= settings('edgeHoverSizeRatio');
|
||||
|
||||
context.save();
|
||||
|
||||
context.setLineDash([2]);
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = size;
|
||||
context.beginPath();
|
||||
context.moveTo(
|
||||
source[prefix + 'x'],
|
||||
source[prefix + 'y']
|
||||
);
|
||||
context.lineTo(
|
||||
target[prefix + 'x'],
|
||||
target[prefix + 'y']
|
||||
);
|
||||
context.stroke();
|
||||
|
||||
context.restore();
|
||||
};
|
||||
})();
|
|
@ -0,0 +1,77 @@
|
|||
;(function() {
|
||||
'use strict';
|
||||
|
||||
sigma.utils.pkg('sigma.canvas.edgehovers');
|
||||
|
||||
/**
|
||||
* This hover renderer will display the edge with a different color or size.
|
||||
*
|
||||
* @param {object} edge The edge object.
|
||||
* @param {object} source node The edge source node.
|
||||
* @param {object} target node The edge target node.
|
||||
* @param {CanvasRenderingContext2D} context The canvas context.
|
||||
* @param {configurable} settings The settings function.
|
||||
*/
|
||||
sigma.canvas.edgehovers.parallel =
|
||||
function(edge, source, target, context, settings) {
|
||||
var color = edge.active ?
|
||||
edge.active_color || settings('defaultEdgeActiveColor') :
|
||||
edge.color,
|
||||
prefix = settings('prefix') || '',
|
||||
size = edge[prefix + 'size'] || 1,
|
||||
edgeColor = settings('edgeColor'),
|
||||
defaultNodeColor = settings('defaultNodeColor'),
|
||||
defaultEdgeColor = settings('defaultEdgeColor'),
|
||||
sX = source[prefix + 'x'],
|
||||
sY = source[prefix + 'y'],
|
||||
tX = target[prefix + 'x'],
|
||||
tY = target[prefix + 'y'],
|
||||
c,
|
||||
d,
|
||||
dist = sigma.utils.getDistance(sX, sY, tX, tY);
|
||||
|
||||
if (!color)
|
||||
switch (edgeColor) {
|
||||
case 'source':
|
||||
color = source.color || defaultNodeColor;
|
||||
break;
|
||||
case 'target':
|
||||
color = target.color || defaultNodeColor;
|
||||
break;
|
||||
default:
|
||||
color = defaultEdgeColor;
|
||||
break;
|
||||
}
|
||||
|
||||
if (settings('edgeHoverColor') === 'edge') {
|
||||
color = edge.hover_color || color;
|
||||
} else {
|
||||
color = edge.hover_color || settings('defaultEdgeHoverColor') || color;
|
||||
}
|
||||
size *= settings('edgeHoverSizeRatio');
|
||||
|
||||
// Intersection points of the source node circle:
|
||||
c = sigma.utils.getCircleIntersection(sX, sY, size, tX, tY, dist);
|
||||
|
||||
// Intersection points of the target node circle:
|
||||
d = sigma.utils.getCircleIntersection(tX, tY, size, sX, sY, dist);
|
||||
|
||||
context.save();
|
||||
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = size;
|
||||
context.beginPath();
|
||||
context.moveTo(c.xi, c.yi);
|
||||
context.lineTo(d.xi_prime, d.yi_prime);
|
||||
context.closePath();
|
||||
context.stroke();
|
||||
|
||||
context.beginPath();
|
||||
context.moveTo(c.xi_prime, c.yi_prime);
|
||||
context.lineTo(d.xi, d.yi);
|
||||
context.closePath();
|
||||
context.stroke();
|
||||
|
||||
context.restore();
|
||||
};
|
||||
})();
|
|
@ -0,0 +1,74 @@
|
|||
;(function() {
|
||||
'use strict';
|
||||
|
||||
sigma.utils.pkg('sigma.canvas.edgehovers');
|
||||
|
||||
/**
|
||||
* This hover renderer will display the edge with a different color or size.
|
||||
*
|
||||
* @param {object} edge The edge object.
|
||||
* @param {object} source node The edge source node.
|
||||
* @param {object} target node The edge target node.
|
||||
* @param {CanvasRenderingContext2D} context The canvas context.
|
||||
* @param {configurable} settings The settings function.
|
||||
*/
|
||||
sigma.canvas.edgehovers.tapered =
|
||||
function(edge, source, target, context, settings) {
|
||||
// The goal is to draw a triangle where the target node is a point of
|
||||
// the triangle, and the two other points are the intersection of the
|
||||
// source circle and the circle (target, distance(source, target)).
|
||||
var color = edge.active ?
|
||||
edge.active_color || settings('defaultEdgeActiveColor') :
|
||||
edge.color,
|
||||
prefix = settings('prefix') || '',
|
||||
size = edge[prefix + 'size'] || 1,
|
||||
edgeColor = settings('edgeColor'),
|
||||
prefix = settings('prefix') || '',
|
||||
defaultNodeColor = settings('defaultNodeColor'),
|
||||
defaultEdgeColor = settings('defaultEdgeColor'),
|
||||
sX = source[prefix + 'x'],
|
||||
sY = source[prefix + 'y'],
|
||||
tX = target[prefix + 'x'],
|
||||
tY = target[prefix + 'y'],
|
||||
dist = sigma.utils.getDistance(sX, sY, tX, tY);
|
||||
|
||||
if (!color)
|
||||
switch (edgeColor) {
|
||||
case 'source':
|
||||
color = source.color || defaultNodeColor;
|
||||
break;
|
||||
case 'target':
|
||||
color = target.color || defaultNodeColor;
|
||||
break;
|
||||
default:
|
||||
color = defaultEdgeColor;
|
||||
break;
|
||||
}
|
||||
|
||||
if (settings('edgeHoverColor') === 'edge') {
|
||||
color = edge.hover_color || color;
|
||||
} else {
|
||||
color = edge.hover_color || settings('defaultEdgeHoverColor') || color;
|
||||
}
|
||||
size *= settings('edgeHoverSizeRatio');
|
||||
|
||||
// Intersection points:
|
||||
var c = sigma.utils.getCircleIntersection(sX, sY, size, tX, tY, dist);
|
||||
|
||||
context.save();
|
||||
|
||||
// Turn transparency on:
|
||||
context.globalAlpha = 0.65;
|
||||
|
||||
// Draw the triangle:
|
||||
context.fillStyle = color;
|
||||
context.beginPath();
|
||||
context.moveTo(tX, tY);
|
||||
context.lineTo(c.xi, c.yi);
|
||||
context.lineTo(c.xi_prime, c.yi_prime);
|
||||
context.closePath();
|
||||
context.fill();
|
||||
|
||||
context.restore();
|
||||
};
|
||||
})();
|
|
@ -0,0 +1,64 @@
|
|||
;(function() {
|
||||
'use strict';
|
||||
|
||||
sigma.utils.pkg('sigma.canvas.edges');
|
||||
|
||||
/**
|
||||
* This method renders the edge as a dashed line.
|
||||
*
|
||||
* @param {object} edge The edge object.
|
||||
* @param {object} source node The edge source node.
|
||||
* @param {object} target node The edge target node.
|
||||
* @param {CanvasRenderingContext2D} context The canvas context.
|
||||
* @param {configurable} settings The settings function.
|
||||
*/
|
||||
sigma.canvas.edges.dashed = function(edge, source, target, context, settings) {
|
||||
var color = edge.active ?
|
||||
edge.active_color || settings('defaultEdgeActiveColor') :
|
||||
edge.color,
|
||||
prefix = settings('prefix') || '',
|
||||
size = edge[prefix + 'size'] || 1,
|
||||
edgeColor = settings('edgeColor'),
|
||||
defaultNodeColor = settings('defaultNodeColor'),
|
||||
defaultEdgeColor = settings('defaultEdgeColor');
|
||||
|
||||
if (!color)
|
||||
switch (edgeColor) {
|
||||
case 'source':
|
||||
color = source.color || defaultNodeColor;
|
||||
break;
|
||||
case 'target':
|
||||
color = target.color || defaultNodeColor;
|
||||
break;
|
||||
default:
|
||||
color = defaultEdgeColor;
|
||||
break;
|
||||
}
|
||||
|
||||
context.save();
|
||||
|
||||
if (edge.active) {
|
||||
context.strokeStyle = settings('edgeActiveColor') === 'edge' ?
|
||||
(color || defaultEdgeColor) :
|
||||
settings('defaultEdgeActiveColor');
|
||||
}
|
||||
else {
|
||||
context.strokeStyle = color;
|
||||
}
|
||||
|
||||
context.setLineDash([8,3]);
|
||||
context.lineWidth = size;
|
||||
context.beginPath();
|
||||
context.moveTo(
|
||||
source[prefix + 'x'],
|
||||
source[prefix + 'y']
|
||||
);
|
||||
context.lineTo(
|
||||
target[prefix + 'x'],
|
||||
target[prefix + 'y']
|
||||
);
|
||||
context.stroke();
|
||||
|
||||
context.restore();
|
||||
};
|
||||
})();
|
|
@ -0,0 +1,64 @@
|
|||
;(function() {
|
||||
'use strict';
|
||||
|
||||
sigma.utils.pkg('sigma.canvas.edges');
|
||||
|
||||
/**
|
||||
* This method renders the edge as a dotted line.
|
||||
*
|
||||
* @param {object} edge The edge object.
|
||||
* @param {object} source node The edge source node.
|
||||
* @param {object} target node The edge target node.
|
||||
* @param {CanvasRenderingContext2D} context The canvas context.
|
||||
* @param {configurable} settings The settings function.
|
||||
*/
|
||||
sigma.canvas.edges.dotted = function(edge, source, target, context, settings) {
|
||||
var color = edge.active ?
|
||||
edge.active_color || settings('defaultEdgeActiveColor') :
|
||||
edge.color,
|
||||
prefix = settings('prefix') || '',
|
||||
size = edge[prefix + 'size'] || 1,
|
||||
edgeColor = settings('edgeColor'),
|
||||
defaultNodeColor = settings('defaultNodeColor'),
|
||||
defaultEdgeColor = settings('defaultEdgeColor');
|
||||
|
||||
if (!color)
|
||||
switch (edgeColor) {
|
||||
case 'source':
|
||||
color = source.color || defaultNodeColor;
|
||||
break;
|
||||
case 'target':
|
||||
color = target.color || defaultNodeColor;
|
||||
break;
|
||||
default:
|
||||
color = defaultEdgeColor;
|
||||
break;
|
||||
}
|
||||
|
||||
context.save();
|
||||
|
||||
if (edge.active) {
|
||||
context.strokeStyle = settings('edgeActiveColor') === 'edge' ?
|
||||
(color || defaultEdgeColor) :
|
||||
settings('defaultEdgeActiveColor');
|
||||
}
|
||||
else {
|
||||
context.strokeStyle = color;
|
||||
}
|
||||
|
||||
context.setLineDash([2]);
|
||||
context.lineWidth = size;
|
||||
context.beginPath();
|
||||
context.moveTo(
|
||||
source[prefix + 'x'],
|
||||
source[prefix + 'y']
|
||||
);
|
||||
context.lineTo(
|
||||
target[prefix + 'x'],
|
||||
target[prefix + 'y']
|
||||
);
|
||||
context.stroke();
|
||||
|
||||
context.restore();
|
||||
};
|
||||
})();
|
|
@ -0,0 +1,77 @@
|
|||
;(function() {
|
||||
'use strict';
|
||||
|
||||
sigma.utils.pkg('sigma.canvas.edges');
|
||||
|
||||
/**
|
||||
* This method renders the edge as two parallel lines.
|
||||
*
|
||||
* @param {object} edge The edge object.
|
||||
* @param {object} source node The edge source node.
|
||||
* @param {object} target node The edge target node.
|
||||
* @param {CanvasRenderingContext2D} context The canvas context.
|
||||
* @param {configurable} settings The settings function.
|
||||
*/
|
||||
sigma.canvas.edges.parallel = function(edge, source, target, context, settings) {
|
||||
var color = edge.active ?
|
||||
edge.active_color || settings('defaultEdgeActiveColor') :
|
||||
edge.color,
|
||||
prefix = settings('prefix') || '',
|
||||
size = edge[prefix + 'size'] || 1,
|
||||
edgeColor = settings('edgeColor'),
|
||||
defaultNodeColor = settings('defaultNodeColor'),
|
||||
defaultEdgeColor = settings('defaultEdgeColor'),
|
||||
sX = source[prefix + 'x'],
|
||||
sY = source[prefix + 'y'],
|
||||
tX = target[prefix + 'x'],
|
||||
tY = target[prefix + 'y'],
|
||||
c,
|
||||
d,
|
||||
dist = sigma.utils.getDistance(sX, sY, tX, tY);
|
||||
|
||||
if (!color)
|
||||
switch (edgeColor) {
|
||||
case 'source':
|
||||
color = source.color || defaultNodeColor;
|
||||
break;
|
||||
case 'target':
|
||||
color = target.color || defaultNodeColor;
|
||||
break;
|
||||
default:
|
||||
color = defaultEdgeColor;
|
||||
break;
|
||||
}
|
||||
|
||||
// Intersection points of the source node circle:
|
||||
c = sigma.utils.getCircleIntersection(sX, sY, size, tX, tY, dist);
|
||||
|
||||
// Intersection points of the target node circle:
|
||||
d = sigma.utils.getCircleIntersection(tX, tY, size, sX, sY, dist);
|
||||
|
||||
context.save();
|
||||
|
||||
if (edge.active) {
|
||||
context.strokeStyle = settings('edgeActiveColor') === 'edge' ?
|
||||
(color || defaultEdgeColor) :
|
||||
settings('defaultEdgeActiveColor');
|
||||
}
|
||||
else {
|
||||
context.strokeStyle = color;
|
||||
}
|
||||
|
||||
context.lineWidth = size;
|
||||
context.beginPath();
|
||||
context.moveTo(c.xi, c.yi);
|
||||
context.lineTo(d.xi_prime, d.yi_prime);
|
||||
context.closePath();
|
||||
context.stroke();
|
||||
|
||||
context.beginPath();
|
||||
context.moveTo(c.xi_prime, c.yi_prime);
|
||||
context.lineTo(d.xi, d.yi);
|
||||
context.closePath();
|
||||
context.stroke();
|
||||
|
||||
context.restore();
|
||||
};
|
||||
})();
|
|
@ -0,0 +1,77 @@
|
|||
;(function() {
|
||||
'use strict';
|
||||
|
||||
sigma.utils.pkg('sigma.canvas.edges');
|
||||
|
||||
/**
|
||||
* This method renders the edge as a tapered line.
|
||||
* Danny Holten, Petra Isenberg, Jean-Daniel Fekete, and J. Van Wijk (2010)
|
||||
* Performance Evaluation of Tapered, Curved, and Animated Directed-Edge
|
||||
* Representations in Node-Link Graphs. Research Report, Sep 2010.
|
||||
*
|
||||
* @param {object} edge The edge object.
|
||||
* @param {object} source node The edge source node.
|
||||
* @param {object} target node The edge target node.
|
||||
* @param {CanvasRenderingContext2D} context The canvas context.
|
||||
* @param {configurable} settings The settings function.
|
||||
*/
|
||||
sigma.canvas.edges.tapered = function(edge, source, target, context, settings) {
|
||||
// The goal is to draw a triangle where the target node is a point of
|
||||
// the triangle, and the two other points are the intersection of the
|
||||
// source circle and the circle (target, distance(source, target)).
|
||||
var color = edge.active ?
|
||||
edge.active_color || settings('defaultEdgeActiveColor') :
|
||||
edge.color,
|
||||
prefix = settings('prefix') || '',
|
||||
size = edge[prefix + 'size'] || 1,
|
||||
edgeColor = settings('edgeColor'),
|
||||
prefix = settings('prefix') || '',
|
||||
defaultNodeColor = settings('defaultNodeColor'),
|
||||
defaultEdgeColor = settings('defaultEdgeColor'),
|
||||
sX = source[prefix + 'x'],
|
||||
sY = source[prefix + 'y'],
|
||||
tX = target[prefix + 'x'],
|
||||
tY = target[prefix + 'y'],
|
||||
dist = sigma.utils.getDistance(sX, sY, tX, tY);
|
||||
|
||||
if (!color)
|
||||
switch (edgeColor) {
|
||||
case 'source':
|
||||
color = source.color || defaultNodeColor;
|
||||
break;
|
||||
case 'target':
|
||||
color = target.color || defaultNodeColor;
|
||||
break;
|
||||
default:
|
||||
color = defaultEdgeColor;
|
||||
break;
|
||||
}
|
||||
|
||||
// Intersection points:
|
||||
var c = sigma.utils.getCircleIntersection(sX, sY, size, tX, tY, dist);
|
||||
|
||||
context.save();
|
||||
|
||||
if (edge.active) {
|
||||
context.fillStyle = settings('edgeActiveColor') === 'edge' ?
|
||||
(color || defaultEdgeColor) :
|
||||
settings('defaultEdgeActiveColor');
|
||||
}
|
||||
else {
|
||||
context.fillStyle = color;
|
||||
}
|
||||
|
||||
// Turn transparency on:
|
||||
context.globalAlpha = 0.65;
|
||||
|
||||
// Draw the triangle:
|
||||
context.beginPath();
|
||||
context.moveTo(tX, tY);
|
||||
context.lineTo(c.xi, c.yi);
|
||||
context.lineTo(c.xi_prime, c.yi_prime);
|
||||
context.closePath();
|
||||
context.fill();
|
||||
|
||||
context.restore();
|
||||
};
|
||||
})();
|
|
@ -0,0 +1,61 @@
|
|||
sigma.renderers.customShapes
|
||||
==================
|
||||
|
||||
Plugin developed by [Ron Peleg](https://github.com/rpeleg1970).
|
||||
|
||||
---
|
||||
## General
|
||||
This plugin registers custom node shape renderers, and allows adding scaled images on top of them. See the following [example code](../../examples/plugin-customShapes.html) for full usage.
|
||||
|
||||
To use, include all .js files under this folder.
|
||||
|
||||
The plugin implements the `node.borderColor` property to allow control of the (surprise) border color.
|
||||
|
||||
## Shapes
|
||||
The plugin implements the following shapes. To set a shape renderer, you simply set `node.type='shape-name'` e.g. `node.type='star'`. The default renderer implemented by sigma.js is named `def` - see also [generic custom node renderer example](../../examples/custom-node-renderer.html)
|
||||
* `circle`: similar to the `def` renderer, but also allows images
|
||||
* `square`
|
||||
* `diamond`
|
||||
* `equilateral`: equilateral polygon. you can control additional properties in this polygon by setting more values as follows:
|
||||
````javascript
|
||||
node.equilateral = {
|
||||
rotate: /* rotate right, value in deg */,
|
||||
numPoints: /* default 5, integer */
|
||||
}
|
||||
````
|
||||
* `star`: you can control additional properties in this star by setting more as follows:
|
||||
````javascript
|
||||
node.star = {
|
||||
numPoints: /* default 5, integer */,
|
||||
innerRatio: /* ratio of inner radius in star, compared to node.size */
|
||||
}
|
||||
````
|
||||
* `cross`: plus shape. you can control additional properties in this polygon by setting more values as follows:
|
||||
````javascript
|
||||
node.cross = {
|
||||
lineWeight: /* width of cross arms */,
|
||||
}
|
||||
````
|
||||
* `pacman`: an example of a more exotic renderer
|
||||
|
||||
The list of available renderer types can be obtained by calling `ShapeLibrary.enumerate()`
|
||||
|
||||
## Images
|
||||
You can add an image to any node, simply by adding `node.image` property, with the following content:
|
||||
````javascript
|
||||
node.image = {
|
||||
url: /* mandatory image URL */,
|
||||
clip: /* Ratio of image clipping disk compared to node size (def 1.0) - see example to how we adapt this to differenmt shapes */,
|
||||
scale: /* Ratio of how to scale the image, compared to node size, default 1.0 */,
|
||||
w: /* numeric width - important for correct scaling if w/h ratio is not 1.0 */,
|
||||
h: /* numeric height - important for correct scaling if w/h ratio is not 1.0 */
|
||||
}
|
||||
````
|
||||
Because the plug-in calls the sigma instance `refresh()` method on image loading, you MUST init as follows or you will not see rendered images:
|
||||
````javascript
|
||||
s = new sigma({
|
||||
...
|
||||
});
|
||||
CustomShapes.init(s);
|
||||
s.refresh();
|
||||
````
|
|
@ -0,0 +1,162 @@
|
|||
;(function(undefined) {
|
||||
'use strict';
|
||||
|
||||
var shapes = [];
|
||||
var register = function(name,drawShape,drawBorder) {
|
||||
shapes.push({
|
||||
'name': name,
|
||||
'drawShape': drawShape,
|
||||
'drawBorder': drawBorder
|
||||
});
|
||||
}
|
||||
|
||||
var enumerateShapes = function() {
|
||||
return shapes;
|
||||
}
|
||||
|
||||
/**
|
||||
* For the standard closed shapes - the shape fill and border are drawn the
|
||||
* same, with some minor differences for fill and border. To facilitate this we
|
||||
* create the generic draw functions, that take a shape drawing func and
|
||||
* return a shape-renderer/border-renderer
|
||||
* ----------
|
||||
*/
|
||||
var genericDrawShape = function(shapeFunc) {
|
||||
return function(node,x,y,size,color,context) {
|
||||
context.fillStyle = color;
|
||||
context.beginPath();
|
||||
shapeFunc(node,x,y,size,context);
|
||||
context.closePath();
|
||||
context.fill();
|
||||
};
|
||||
}
|
||||
|
||||
var genericDrawBorder = function(shapeFunc) {
|
||||
return function(node,x,y,size,color,context) {
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = size / 5;
|
||||
context.beginPath();
|
||||
shapeFunc(node,x,y,size,context);
|
||||
context.closePath();
|
||||
context.stroke();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* We now proced to use the generics to define our standard shape/border
|
||||
* drawers: square, diamond, equilateral (polygon), and star
|
||||
* ----------
|
||||
*/
|
||||
var drawSquare = function(node,x,y,size,context) {
|
||||
var rotate = Math.PI*45/180; // 45 deg rotation of a diamond shape
|
||||
context.moveTo(x+size*Math.sin(rotate), y-size*Math.cos(rotate)); // first point on outer radius, dwangle 'rotate'
|
||||
for(var i=1; i<4; i++) {
|
||||
context.lineTo(x+Math.sin(rotate+2*Math.PI*i/4)*size, y-Math.cos(rotate+2*Math.PI*i/4)*size);
|
||||
}
|
||||
}
|
||||
register("square",genericDrawShape(drawSquare),genericDrawBorder(drawSquare));
|
||||
|
||||
var drawCircle = function(node,x,y,size,context) {
|
||||
context.arc(x,y,size,0,Math.PI*2,true);
|
||||
}
|
||||
register("circle",genericDrawShape(drawCircle),genericDrawBorder(drawCircle));
|
||||
|
||||
var drawDiamond = function(node,x,y,size,context) {
|
||||
context.moveTo(x-size, y);
|
||||
context.lineTo(x, y-size);
|
||||
context.lineTo(x+size, y);
|
||||
context.lineTo(x, y+size);
|
||||
}
|
||||
register("diamond",genericDrawShape(drawDiamond),genericDrawBorder(drawDiamond));
|
||||
|
||||
var drawCross = function(node,x,y,size,context) {
|
||||
var lineWeight = (node.cross && node.cross.lineWeight) || 5;
|
||||
context.moveTo(x-size, y-lineWeight);
|
||||
context.lineTo(x-size, y+lineWeight);
|
||||
context.lineTo(x-lineWeight, y+lineWeight);
|
||||
context.lineTo(x-lineWeight, y+size);
|
||||
context.lineTo(x+lineWeight, y+size);
|
||||
context.lineTo(x+lineWeight, y+lineWeight);
|
||||
context.lineTo(x+size, y+lineWeight);
|
||||
context.lineTo(x+size, y-lineWeight);
|
||||
context.lineTo(x+lineWeight, y-lineWeight);
|
||||
context.lineTo(x+lineWeight, y-size);
|
||||
context.lineTo(x-lineWeight, y-size);
|
||||
context.lineTo(x-lineWeight, y-lineWeight);
|
||||
}
|
||||
register("cross",genericDrawShape(drawCross),genericDrawBorder(drawCross));
|
||||
|
||||
var drawEquilateral = function(node,x,y,size,context) {
|
||||
var pcount = (node.equilateral && node.equilateral.numPoints) || 5;
|
||||
var rotate = ((node.equilateral && node.equilateral.rotate) || 0)*Math.PI/180;
|
||||
var radius = size;
|
||||
context.moveTo(x+radius*Math.sin(rotate), y-radius*Math.cos(rotate)); // first point on outer radius, angle 'rotate'
|
||||
for(var i=1; i<pcount; i++) {
|
||||
context.lineTo(x+Math.sin(rotate+2*Math.PI*i/pcount)*radius, y-Math.cos(rotate+2*Math.PI*i/pcount)*radius);
|
||||
}
|
||||
}
|
||||
register("equilateral",genericDrawShape(drawEquilateral),genericDrawBorder(drawEquilateral));
|
||||
|
||||
|
||||
var starShape = function(node,x,y,size,context) {
|
||||
var pcount = (node.star && node.star.numPoints) || 5,
|
||||
inRatio = (node.star && node.star.innerRatio) || 0.5,
|
||||
outR = size,
|
||||
inR = size*inRatio,
|
||||
angleOffset = Math.PI/pcount;
|
||||
context.moveTo(x, y-size); // first point on outer radius, top
|
||||
for(var i=0; i<pcount; i++) {
|
||||
context.lineTo(x+Math.sin(angleOffset+2*Math.PI*i/pcount)*inR,
|
||||
y-Math.cos(angleOffset+2*Math.PI*i/pcount)*inR);
|
||||
context.lineTo(x+Math.sin(2*Math.PI*(i+1)/pcount)*outR,
|
||||
y-Math.cos(2*Math.PI*(i+1)/pcount)*outR);
|
||||
}
|
||||
}
|
||||
register("star",genericDrawShape(starShape),genericDrawBorder(starShape));
|
||||
|
||||
/**
|
||||
* An example of a non standard shape (pacman). Here we WILL NOT use the
|
||||
* genericDraw functions, but rather register a full custom node renderer for
|
||||
* fill, and skip the border renderer which is irrelevant for this shape
|
||||
* ----------
|
||||
*/
|
||||
var drawPacman = function(node,x,y,size,color,context) {
|
||||
context.fillStyle = 'yellow';
|
||||
context.beginPath();
|
||||
context.arc(x,y,size,1.25*Math.PI,0,false);
|
||||
context.arc(x,y,size,0,0.75*Math.PI,false);
|
||||
context.lineTo(x,y);
|
||||
context.closePath();
|
||||
context.fill();
|
||||
|
||||
context.fillStyle = 'white';
|
||||
context.strokeStyle = 'black';
|
||||
context.beginPath();
|
||||
context.arc(x+size/3,y-size/3,size/4,0,2*Math.PI,false);
|
||||
context.closePath();
|
||||
context.fill();
|
||||
context.stroke();
|
||||
|
||||
context.fillStyle = 'black';
|
||||
context.beginPath();
|
||||
context.arc(x+4*size/9,y-size/3,size/8,0,2*Math.PI,false);
|
||||
context.closePath();
|
||||
context.fill();
|
||||
}
|
||||
register("pacman",drawPacman,null);
|
||||
|
||||
/**
|
||||
* Exporting
|
||||
* ----------
|
||||
*/
|
||||
this.ShapeLibrary = {
|
||||
|
||||
// Functions
|
||||
enumerate: enumerateShapes,
|
||||
// add: addShape,
|
||||
|
||||
// Version
|
||||
version: '0.1'
|
||||
};
|
||||
|
||||
}).call(this);
|
|
@ -0,0 +1,236 @@
|
|||
;(function(undefined) {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined')
|
||||
throw 'sigma is not declared';
|
||||
|
||||
if (typeof ShapeLibrary === 'undefined')
|
||||
throw 'ShapeLibrary is not declared';
|
||||
|
||||
|
||||
// Initialize package:
|
||||
sigma.utils.pkg('sigma.canvas.nodes');
|
||||
sigma.utils.pkg('sigma.svg.nodes');
|
||||
|
||||
var sigInst = undefined;
|
||||
var imgCache = {};
|
||||
|
||||
var initPlugin = function(inst) {
|
||||
sigInst = inst;
|
||||
}
|
||||
|
||||
var drawImage = function (node,x,y,size,context) {
|
||||
if(sigInst && node.image && node.image.url) {
|
||||
var url = node.image.url;
|
||||
var ih = node.image.h || 1; // 1 is arbitrary, anyway only the ratio counts
|
||||
var iw = node.image.w || 1;
|
||||
var scale = node.image.scale || 1;
|
||||
var clip = node.image.clip || 1;
|
||||
|
||||
// create new IMG or get from imgCache
|
||||
var image = imgCache[url];
|
||||
if(!image) {
|
||||
image = document.createElement('IMG');
|
||||
image.src = url;
|
||||
image.status = 'loading';
|
||||
image.onerror = function() {
|
||||
console.log("error loading", url);
|
||||
image.status = 'error';
|
||||
};
|
||||
image.onload = function(){
|
||||
// TODO see how we redraw on load
|
||||
// need to provide the siginst as a parameter to the library
|
||||
console.log("redraw on image load", url);
|
||||
image.status = 'ok';
|
||||
sigInst.refresh();
|
||||
};
|
||||
imgCache[url] = image;
|
||||
}
|
||||
|
||||
// calculate position and draw
|
||||
var xratio = (iw<ih) ? (iw/ih) : 1;
|
||||
var yratio = (ih<iw) ? (ih/iw) : 1;
|
||||
var r = size*scale;
|
||||
|
||||
// Draw the clipping disc:
|
||||
context.save(); // enter clipping mode
|
||||
context.beginPath();
|
||||
context.arc(x,y,size*clip,0,Math.PI*2,true);
|
||||
context.closePath();
|
||||
context.clip();
|
||||
|
||||
if(image.status === 'ok') {
|
||||
// Draw the actual image
|
||||
context.drawImage(image,
|
||||
x+Math.sin(-3.142/4)*r*xratio,
|
||||
y-Math.cos(-3.142/4)*r*yratio,
|
||||
r*xratio*2*Math.sin(-3.142/4)*(-1),
|
||||
r*yratio*2*Math.cos(-3.142/4));
|
||||
}
|
||||
context.restore(); // exit clipping mode
|
||||
}
|
||||
}
|
||||
|
||||
var drawSVGImage = function (node, group, settings) {
|
||||
if(sigInst && node.image && node.image.url) {
|
||||
var clipCircle = document.createElementNS(settings('xmlns'), 'circle'),
|
||||
clipPath = document.createElementNS(settings('xmlns'), 'clipPath'),
|
||||
clipPathId = settings('classPrefix') + '-clip-path-' + node.id,
|
||||
def = document.createElementNS(settings('xmlns'), 'defs'),
|
||||
image = document.createElementNS(settings('xmlns'), 'image'),
|
||||
url = node.image.url;
|
||||
|
||||
clipPath.setAttributeNS(null, 'id', clipPathId);
|
||||
clipPath.appendChild(clipCircle);
|
||||
def.appendChild(clipPath);
|
||||
|
||||
// angular's base tag will change the relative fragment id, so
|
||||
// #<clipPathId> doesn't work
|
||||
// HACKHACK: IE <=9 does not respect the HTML base element in SVG.
|
||||
// They don't need the current URL in the clip path reference.
|
||||
var absolutePath = /MSIE [5-9]/.test(navigator.userAgent) ?
|
||||
"" : document.location.href;
|
||||
// To fix cases where an anchor tag was used
|
||||
absolutePath = absolutePath.split("#")[0];
|
||||
image.setAttributeNS(null, 'class',
|
||||
settings('classPrefix') + '-node-image');
|
||||
image.setAttributeNS(null, 'clip-path',
|
||||
'url(' + absolutePath + '#' + clipPathId + ')');
|
||||
image.setAttributeNS(null, 'pointer-events', 'none');
|
||||
image.setAttributeNS('http://www.w3.org/1999/xlink', 'href',
|
||||
node.image.url);
|
||||
group.appendChild(def);
|
||||
group.appendChild(image);
|
||||
}
|
||||
}
|
||||
|
||||
var register = function(name,drawShape,drawBorder) {
|
||||
sigma.canvas.nodes[name] = function(node, context, settings) {
|
||||
var args = arguments,
|
||||
prefix = settings('prefix') || '',
|
||||
size = node[prefix + 'size'],
|
||||
color = node.color || settings('defaultNodeColor'),
|
||||
borderColor = node.borderColor || color,
|
||||
x = node[prefix + 'x'],
|
||||
y = node[prefix + 'y'];
|
||||
|
||||
context.save();
|
||||
|
||||
if(drawShape) {
|
||||
drawShape(node,x,y,size,color,context);
|
||||
}
|
||||
|
||||
if(drawBorder) {
|
||||
drawBorder(node,x,y,size,borderColor,context);
|
||||
}
|
||||
|
||||
drawImage(node,x,y,size,context);
|
||||
|
||||
context.restore();
|
||||
};
|
||||
|
||||
sigma.svg.nodes[name] = {
|
||||
create: function(node, settings) {
|
||||
var group = document.createElementNS(settings('xmlns'), 'g'),
|
||||
circle = document.createElementNS(settings('xmlns'), 'circle');
|
||||
|
||||
group.setAttributeNS(null, 'class',
|
||||
settings('classPrefix') + '-node-group');
|
||||
group.setAttributeNS(null, 'data-node-id', node.id);
|
||||
// Defining the node's circle
|
||||
circle.setAttributeNS(null, 'data-node-id', node.id);
|
||||
circle.setAttributeNS(null, 'class',
|
||||
settings('classPrefix') + '-node');
|
||||
circle.setAttributeNS(null, 'fill',
|
||||
node.color || settings('defaultNodeColor'));
|
||||
|
||||
group.appendChild(circle);
|
||||
drawSVGImage(node, group, settings);
|
||||
return group;
|
||||
},
|
||||
update: function(node, group, settings) {
|
||||
var classPrefix = settings('classPrefix'),
|
||||
clip = node.image.clip || 1,
|
||||
// 1 is arbitrary, anyway only the ratio counts
|
||||
ih = node.image.h || 1,
|
||||
iw = node.image.w || 1,
|
||||
prefix = settings('prefix') || '',
|
||||
scale = node.image.scale || 1,
|
||||
size = node[prefix + 'size'],
|
||||
x = node[prefix + 'x'],
|
||||
y = node[prefix + 'y'];
|
||||
|
||||
var r = scale * size,
|
||||
xratio = (iw<ih) ? (iw/ih) : 1,
|
||||
yratio = (ih<iw) ? (ih/iw) : 1;
|
||||
|
||||
for(var i = 0, childNodes = group.childNodes; i < childNodes.length; i ++) {
|
||||
var className = childNodes[i].getAttribute('class');
|
||||
|
||||
switch (className) {
|
||||
case classPrefix + '-node':
|
||||
childNodes[i].setAttributeNS(null, 'cx', x);
|
||||
childNodes[i].setAttributeNS(null, 'cy', y);
|
||||
childNodes[i].setAttributeNS(null, 'r', size);
|
||||
|
||||
// // Updating only if not freestyle
|
||||
if (!settings('freeStyle')) {
|
||||
childNodes[i].setAttributeNS(
|
||||
null,
|
||||
'fill',
|
||||
node.color || settings('defaultNodeColor'));
|
||||
}
|
||||
break;
|
||||
case classPrefix + '-node-image':
|
||||
childNodes[i].setAttributeNS(null, 'x',
|
||||
x+Math.sin(-3.142/4)*r*xratio);
|
||||
childNodes[i].setAttributeNS(null, 'y',
|
||||
y-Math.cos(-3.142/4)*r*yratio);
|
||||
childNodes[i].setAttributeNS(null, 'width',
|
||||
r*xratio*2*Math.sin(-3.142/4)*(-1));
|
||||
childNodes[i].setAttributeNS(null, 'height',
|
||||
r*yratio*2*Math.cos(-3.142/4));
|
||||
break;
|
||||
default:
|
||||
// no class name, must be the clip-path
|
||||
var clipPath = childNodes[i].firstChild;
|
||||
if (clipPath != null) {
|
||||
var clipPathId = classPrefix + '-clip-path-' + node.id;
|
||||
if (clipPath.getAttribute('id') === clipPathId) {
|
||||
clipPath.firstChild.setAttributeNS(null, 'cx', x);
|
||||
clipPath.firstChild.setAttributeNS(null, 'cy', y);
|
||||
clipPath.firstChild.setAttributeNS(null, 'r',
|
||||
clip * size);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// showing
|
||||
group.style.display = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShapeLibrary.enumerate().forEach(function(shape) {
|
||||
register(shape.name,shape.drawShape,shape.drawBorder);
|
||||
});
|
||||
|
||||
/**
|
||||
* Exporting
|
||||
* ----------
|
||||
*/
|
||||
this.CustomShapes = {
|
||||
|
||||
// Functions
|
||||
init: initPlugin,
|
||||
// add pre-cache images
|
||||
|
||||
// Version
|
||||
version: '0.1'
|
||||
};
|
||||
|
||||
|
||||
|
||||
}).call(this);
|
|
@ -0,0 +1,38 @@
|
|||
sigma.renderers.edgeDots
|
||||
========================
|
||||
|
||||
Plugin developed by [Joakim af Sandeberg](https://github.com/jotunacorn).
|
||||
|
||||
Contact: joakim.afs+github@gmail.com
|
||||
|
||||
---
|
||||
## General
|
||||
This plugin adds the option to show colored dots near the source and target of an edge when using the canvas renderer.
|
||||
|
||||
See the following [example](../../examples/plugin-edgeDots.html) for full usage.
|
||||
|
||||
To use it, include all .js files under this folder.
|
||||
|
||||
## Edges
|
||||
|
||||
This plugin extends Sigma.js canvas edges:
|
||||
* **sourceDotColor**
|
||||
* The value to use as color for the source dot. If left undefined there will be no dot at the source.
|
||||
* type: *string*
|
||||
* default value: undefined
|
||||
* **targetDotColor**
|
||||
* The value to use as color for the target dot. If left undefined there will be no dot at the target.
|
||||
* type: *string*
|
||||
* default value: undefined
|
||||
* **dotOffset**
|
||||
* The value which define the distance between the dots and the nodes, relative to the node size.
|
||||
* type: *number*
|
||||
* default value: 3
|
||||
* **dotSize**
|
||||
* The value which define the size of the dot relative to the edge.
|
||||
* type: *number*
|
||||
* default value: 1
|
||||
## Renderers
|
||||
|
||||
This plugin modifies the sigma.canvas.edges.curve and sigma.canvas.edges.curvedArrow
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
;(function() {
|
||||
'use strict';
|
||||
|
||||
sigma.utils.pkg('sigma.canvas.edges');
|
||||
|
||||
/**
|
||||
* This edge renderer will display edges as curves.
|
||||
*
|
||||
* @param {object} edge The edge object.
|
||||
* @param {object} source node The edge source node.
|
||||
* @param {object} target node The edge target node.
|
||||
* @param {CanvasRenderingContext2D} context The canvas context.
|
||||
* @param {configurable} settings The settings function.
|
||||
*/
|
||||
sigma.canvas.edges.dotCurve = function(edge, source, target, context, settings) {
|
||||
var color = edge.color,
|
||||
prefix = settings('prefix') || '',
|
||||
size = edge[prefix + 'size'] || 1,
|
||||
edgeColor = settings('edgeColor'),
|
||||
defaultNodeColor = settings('defaultNodeColor'),
|
||||
defaultEdgeColor = settings('defaultEdgeColor'),
|
||||
cp = {},
|
||||
sSize = source[prefix + 'size'],
|
||||
sX = source[prefix + 'x'],
|
||||
sY = source[prefix + 'y'],
|
||||
tX = target[prefix + 'x'],
|
||||
tY = target[prefix + 'y'];
|
||||
|
||||
cp = (source.id === target.id) ?
|
||||
sigma.utils.getSelfLoopControlPoints(sX, sY, sSize) :
|
||||
sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY);
|
||||
|
||||
if (!color)
|
||||
switch (edgeColor) {
|
||||
case 'source':
|
||||
color = source.color || defaultNodeColor;
|
||||
break;
|
||||
case 'target':
|
||||
color = target.color || defaultNodeColor;
|
||||
break;
|
||||
default:
|
||||
color = defaultEdgeColor;
|
||||
break;
|
||||
}
|
||||
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = size;
|
||||
context.beginPath();
|
||||
context.moveTo(sX, sY);
|
||||
if (source.id === target.id) {
|
||||
context.bezierCurveTo(cp.x1, cp.y1, cp.x2, cp.y2, tX, tY);
|
||||
} else {
|
||||
context.quadraticCurveTo(cp.x, cp.y, tX, tY);
|
||||
}
|
||||
context.stroke();
|
||||
if(edge.sourceDotColor != undefined || edge.targetDotColor != undefined) {
|
||||
var dotOffset = edge.dotOffset || 3;
|
||||
var dotSize = edge.dotSize || 1;
|
||||
dotSize = size*dotSize;
|
||||
dotOffset = dotOffset*sSize;
|
||||
if(edge.sourceDotColor != undefined) {
|
||||
createDot(context, sX, sY, cp, tX, tY, dotOffset, dotSize, edge.sourceDotColor);
|
||||
}
|
||||
if (edge.targetDotColor != undefined){
|
||||
createDot(context, tX, tY, cp, sX, sY, dotOffset, dotSize, edge.targetDotColor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function createDot(context, sX, sY, cp, tX, tY, offset, size, color) {
|
||||
context.beginPath();
|
||||
context.fillStyle = color;
|
||||
var dot = getPointOnBezier(sX, sY, cp.x, cp.y, tX, tY,
|
||||
offset);
|
||||
context.arc(dot.x, dot.y, size * 3, 0, 2 * Math.PI,
|
||||
false);
|
||||
context.fill();
|
||||
}
|
||||
|
||||
function getQBezierValue(t, p1, p2, p3) {
|
||||
var iT = 1 - t;
|
||||
return iT * iT * p1 + 2 * iT * t * p2 + t * t * p3;
|
||||
}
|
||||
|
||||
function getQuadraticCurvePoint(startX, startY, cpX, cpY, endX, endY, position) {
|
||||
return {
|
||||
x:getQBezierValue(position, startX, cpX, endX),
|
||||
y:getQBezierValue(position, startY, cpY, endY)
|
||||
};
|
||||
}
|
||||
function getDistanceBetweenPoints(x1, y1, x2, y2){
|
||||
return Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
|
||||
}
|
||||
/* Function to get a point on a bezier curve a certain distance away from
|
||||
its source. Needed since the position on a beziercurve is given to the
|
||||
formula as a percentage (t).*/
|
||||
function getPointOnBezier(startX, startY, cpX, cpY, endX, endY, distance){
|
||||
var bestT = 0;
|
||||
var bestAccuracy = 1000;
|
||||
var stepSize = 0.001;
|
||||
for(var t = 0; t<1; t+=stepSize){
|
||||
var currentPoint = getQuadraticCurvePoint(startX, startY, cpX, cpY,
|
||||
endX, endY, t);
|
||||
var currentDistance = getDistanceBetweenPoints(startX, startY,
|
||||
currentPoint.x, currentPoint.y);
|
||||
if(Math.abs(currentDistance-distance) < bestAccuracy){
|
||||
bestAccuracy = Math.abs(currentDistance-distance);
|
||||
bestT = t;
|
||||
}
|
||||
}
|
||||
return getQuadraticCurvePoint(startX, startY, cpX, cpY, endX, endY, bestT);
|
||||
}
|
||||
|
||||
})();
|
|
@ -0,0 +1,145 @@
|
|||
;(function() {
|
||||
'use strict';
|
||||
|
||||
sigma.utils.pkg('sigma.canvas.edges');
|
||||
|
||||
/**
|
||||
* This edge renderer will display edges as curves with arrow heading.
|
||||
*
|
||||
* @param {object} edge The edge object.
|
||||
* @param {object} source node The edge source node.
|
||||
* @param {object} target node The edge target node.
|
||||
* @param {CanvasRenderingContext2D} context The canvas context.
|
||||
* @param {configurable} settings The settings function.
|
||||
*/
|
||||
sigma.canvas.edges.dotCurvedArrow =
|
||||
function(edge, source, target, context, settings) {
|
||||
var color = edge.color,
|
||||
prefix = settings('prefix') || '',
|
||||
edgeColor = settings('edgeColor'),
|
||||
defaultNodeColor = settings('defaultNodeColor'),
|
||||
defaultEdgeColor = settings('defaultEdgeColor'),
|
||||
cp = {},
|
||||
size = edge[prefix + 'size'] || 1,
|
||||
count = edge.count || 0,
|
||||
tSize = target[prefix + 'size'],
|
||||
sX = source[prefix + 'x'],
|
||||
sY = source[prefix + 'y'],
|
||||
tX = target[prefix + 'x'],
|
||||
tY = target[prefix + 'y'],
|
||||
aSize = Math.max(size * 2.5, settings('minArrowSize')),
|
||||
d,
|
||||
aX,
|
||||
aY,
|
||||
vX,
|
||||
vY;
|
||||
|
||||
cp = (source.id === target.id) ?
|
||||
sigma.utils.getSelfLoopControlPoints(sX, sY, tSize, count) :
|
||||
sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY, count);
|
||||
|
||||
if (source.id === target.id) {
|
||||
d = Math.sqrt(Math.pow(tX - cp.x1, 2) + Math.pow(tY - cp.y1, 2));
|
||||
aX = cp.x1 + (tX - cp.x1) * (d - aSize - tSize) / d;
|
||||
aY = cp.y1 + (tY - cp.y1) * (d - aSize - tSize) / d;
|
||||
vX = (tX - cp.x1) * aSize / d;
|
||||
vY = (tY - cp.y1) * aSize / d;
|
||||
}
|
||||
else {
|
||||
d = Math.sqrt(Math.pow(tX - cp.x, 2) + Math.pow(tY - cp.y, 2));
|
||||
aX = cp.x + (tX - cp.x) * (d - aSize - tSize) / d;
|
||||
aY = cp.y + (tY - cp.y) * (d - aSize - tSize) / d;
|
||||
vX = (tX - cp.x) * aSize / d;
|
||||
vY = (tY - cp.y) * aSize / d;
|
||||
}
|
||||
|
||||
if (!color)
|
||||
switch (edgeColor) {
|
||||
case 'source':
|
||||
color = source.color || defaultNodeColor;
|
||||
break;
|
||||
case 'target':
|
||||
color = target.color || defaultNodeColor;
|
||||
break;
|
||||
default:
|
||||
color = defaultEdgeColor;
|
||||
break;
|
||||
}
|
||||
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = size;
|
||||
context.beginPath();
|
||||
context.moveTo(sX, sY);
|
||||
if (source.id === target.id) {
|
||||
context.bezierCurveTo(cp.x2, cp.y2, cp.x1, cp.y1, aX, aY);
|
||||
} else {
|
||||
context.quadraticCurveTo(cp.x, cp.y, aX, aY);
|
||||
}
|
||||
context.stroke();
|
||||
|
||||
context.fillStyle = color;
|
||||
context.beginPath();
|
||||
context.moveTo(aX + vX, aY + vY);
|
||||
context.lineTo(aX + vY * 0.6, aY - vX * 0.6);
|
||||
context.lineTo(aX - vY * 0.6, aY + vX * 0.6);
|
||||
context.lineTo(aX + vX, aY + vY);
|
||||
context.closePath();
|
||||
context.fill();
|
||||
if(edge.sourceDotColor != undefined || edge.targetDotColor != undefined) {
|
||||
var dotOffset = edge.dotOffset || 3;
|
||||
var dotSize = edge.dotSize || 1;
|
||||
dotSize = size*dotSize;
|
||||
dotOffset = dotOffset*tSize;
|
||||
if(edge.sourceDotColor != undefined) {
|
||||
createDot(context, sX, sY, cp, tX, tY, dotOffset, dotSize, edge.sourceDotColor);
|
||||
}
|
||||
if (edge.targetDotColor != undefined){
|
||||
createDot(context, tX, tY, cp, sX, sY, dotOffset, dotSize, edge.targetDotColor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function createDot(context, sX, sY, cp, tX, tY, offset, size, color) {
|
||||
context.beginPath();
|
||||
context.fillStyle = color;
|
||||
var dot = getPointOnBezier(sX, sY, cp.x, cp.y, tX, tY,
|
||||
offset);
|
||||
context.arc(dot.x, dot.y, size * 3, 0, 2 * Math.PI,
|
||||
false);
|
||||
context.fill();
|
||||
}
|
||||
|
||||
function getQBezierValue(t, p1, p2, p3) {
|
||||
var iT = 1 - t;
|
||||
return iT * iT * p1 + 2 * iT * t * p2 + t * t * p3;
|
||||
}
|
||||
|
||||
function getQuadraticCurvePoint(startX, startY, cpX, cpY, endX, endY, position) {
|
||||
return {
|
||||
x:getQBezierValue(position, startX, cpX, endX),
|
||||
y:getQBezierValue(position, startY, cpY, endY)
|
||||
};
|
||||
}
|
||||
function getDistanceBetweenPoints(x1, y1, x2, y2){
|
||||
return Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
|
||||
}
|
||||
/* Function to get a point on a bezier curve a certain distance away from
|
||||
its source. Needed since the position on a beziercurve is given to the
|
||||
formula as a percentage (t).*/
|
||||
function getPointOnBezier(startX, startY, cpX, cpY, endX, endY, distance){
|
||||
var bestT = 0;
|
||||
var bestAccuracy = 1000;
|
||||
var stepSize = 0.001;
|
||||
for(var t = 0; t<1; t+=stepSize){
|
||||
var currentPoint = getQuadraticCurvePoint(startX, startY, cpX, cpY,
|
||||
endX, endY, t);
|
||||
var currentDistance = getDistanceBetweenPoints(startX, startY,
|
||||
currentPoint.x, currentPoint.y);
|
||||
if(Math.abs(currentDistance-distance) < bestAccuracy){
|
||||
bestAccuracy = Math.abs(currentDistance-distance);
|
||||
bestT = t;
|
||||
}
|
||||
}
|
||||
return getQuadraticCurvePoint(startX, startY, cpX, cpY, endX, endY, bestT);
|
||||
}
|
||||
})();
|
|
@ -0,0 +1,76 @@
|
|||
sigma.renderers.edgeLabels
|
||||
==================
|
||||
|
||||
Plugin developed by [Sébastien Heymann](https://github.com/sheymann) for [Linkurious](https://github.com/Linkurious).
|
||||
|
||||
Contact: seb@linkurio.us
|
||||
|
||||
---
|
||||
## General
|
||||
This plugin displays edge labels.
|
||||
|
||||
See the following [example](../../examples/edge-renderers.html) for full usage.
|
||||
|
||||
To use it, include all .js files under this folder.
|
||||
|
||||
## Settings
|
||||
|
||||
This plugin extends Sigma.js settings in a transparent way to render edge labels, see [settings.js](settings.js):
|
||||
|
||||
* **defaultEdgeLabelColor**
|
||||
* type: *string*
|
||||
* default value: `#000`
|
||||
|
||||
* **defaultEdgeLabelActiveColor**
|
||||
* type: *string*
|
||||
* default value: `rgb(236, 81, 72)`
|
||||
|
||||
* **defaultEdgeLabelSize**
|
||||
* type: *number*
|
||||
* default value: `10`
|
||||
|
||||
* **edgeLabelSize**
|
||||
* Indicates how to choose the edge labels size.
|
||||
* type: *string*
|
||||
* default value: `fixed`
|
||||
* available values: `fixed`, `proportional`
|
||||
|
||||
* **edgeLabelSizePowRatio**
|
||||
* The opposite power ratio between the font size of the label and the edge size.
|
||||
* type: *number*
|
||||
* default value: `0.8`
|
||||
|
||||
````javascript
|
||||
// Formula:
|
||||
Math.pow(size, - 1 / edgeLabelSizePowRatio) * size * defaultEdgeLabelSize
|
||||
````
|
||||
|
||||
* **edgeLabelThreshold**
|
||||
* The minimum size an edge must have to see its label displayed.
|
||||
* type: *number*
|
||||
* default value: `1`
|
||||
|
||||
The plugin also forces `drawEdgeLabels` to `true`.
|
||||
|
||||
The default values provided by the plugin may be overridden when instantiating Sigma, e.g.:
|
||||
|
||||
````javascript
|
||||
var sigInst = new sigma({
|
||||
container: 'graph-container',
|
||||
settings: {
|
||||
edgeLabelSize: 'proportional'
|
||||
}
|
||||
});
|
||||
````
|
||||
|
||||
## Renderers
|
||||
|
||||
This plugin provides the following edge label renderers:
|
||||
- `line` (default)
|
||||
- `arrow` (use default)
|
||||
- `curve`
|
||||
- `curvedArrow`
|
||||
|
||||
## Compatibility
|
||||
|
||||
This plugin is compatible with `sigma.plugins.activeState`.
|
|
@ -0,0 +1,41 @@
|
|||
;(function(undefined) {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined')
|
||||
throw 'sigma is not declared';
|
||||
|
||||
// Initialize package:
|
||||
sigma.utils.pkg('sigma.settings');
|
||||
|
||||
/**
|
||||
* Extended sigma settings for sigma.renderers.edgeLabels.
|
||||
*/
|
||||
var settings = {
|
||||
/**
|
||||
* RENDERERS SETTINGS:
|
||||
* *******************
|
||||
*/
|
||||
// {string}
|
||||
defaultEdgeLabelColor: '#000',
|
||||
// {string}
|
||||
defaultEdgeLabelActiveColor: '#000',
|
||||
// {string}
|
||||
defaultEdgeLabelSize: 10,
|
||||
// {string} Indicates how to choose the edge labels size. Available values:
|
||||
// "fixed", "proportional"
|
||||
edgeLabelSize: 'fixed',
|
||||
// {string} The opposite power ratio between the font size of the label and
|
||||
// the edge size:
|
||||
// Math.pow(size, -1 / edgeLabelSizePowRatio) * size * defaultEdgeLabelSize
|
||||
edgeLabelSizePowRatio: 1,
|
||||
// {number} The minimum size an edge must have to see its label displayed.
|
||||
edgeLabelThreshold: 1,
|
||||
};
|
||||
|
||||
// Export the previously designed settings:
|
||||
sigma.settings = sigma.utils.extend(sigma.settings || {}, settings);
|
||||
|
||||
// Override default settings:
|
||||
sigma.settings.drawEdgeLabels = true;
|
||||
|
||||
}).call(this);
|
|
@ -0,0 +1,112 @@
|
|||
;(function(undefined) {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined')
|
||||
throw 'sigma is not declared';
|
||||
|
||||
// Initialize packages:
|
||||
sigma.utils.pkg('sigma.canvas.edges.labels');
|
||||
|
||||
/**
|
||||
* This label renderer will just display the label on the curve of the edge.
|
||||
* The label is rendered at half distance of the edge extremities, and is
|
||||
* always oriented from left to right on the top side of the curve.
|
||||
*
|
||||
* @param {object} edge The edge object.
|
||||
* @param {object} source node The edge source node.
|
||||
* @param {object} target node The edge target node.
|
||||
* @param {CanvasRenderingContext2D} context The canvas context.
|
||||
* @param {configurable} settings The settings function.
|
||||
*/
|
||||
sigma.canvas.edges.labels.curve =
|
||||
function(edge, source, target, context, settings) {
|
||||
if (typeof edge.label !== 'string')
|
||||
return;
|
||||
|
||||
var prefix = settings('prefix') || '',
|
||||
size = edge[prefix + 'size'] || 1;
|
||||
|
||||
if (size < settings('edgeLabelThreshold'))
|
||||
return;
|
||||
|
||||
var fontSize,
|
||||
sSize = source[prefix + 'size'],
|
||||
sX = source[prefix + 'x'],
|
||||
sY = source[prefix + 'y'],
|
||||
tX = target[prefix + 'x'],
|
||||
tY = target[prefix + 'y'],
|
||||
dX = tX - sX,
|
||||
dY = tY - sY,
|
||||
sign = (sX < tX) ? 1 : -1,
|
||||
cp = {},
|
||||
c,
|
||||
angle,
|
||||
t = 0.5; //length of the curve
|
||||
|
||||
if (source.id === target.id) {
|
||||
cp = sigma.utils.getSelfLoopControlPoints(sX, sY, sSize);
|
||||
c = sigma.utils.getPointOnBezierCurve(
|
||||
t, sX, sY, tX, tY, cp.x1, cp.y1, cp.x2, cp.y2
|
||||
);
|
||||
angle = Math.atan2(1, 1); // 45°
|
||||
} else {
|
||||
cp = sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY);
|
||||
c = sigma.utils.getPointOnQuadraticCurve(t, sX, sY, tX, tY, cp.x, cp.y);
|
||||
angle = Math.atan2(dY * sign, dX * sign);
|
||||
}
|
||||
|
||||
// The font size is sublineraly proportional to the edge size, in order to
|
||||
// avoid very large labels on screen.
|
||||
// This is achieved by f(x) = x * x^(-1/ a), where 'x' is the size and 'a'
|
||||
// is the edgeLabelSizePowRatio. Notice that f(1) = 1.
|
||||
// The final form is:
|
||||
// f'(x) = b * x * x^(-1 / a), thus f'(1) = b. Application:
|
||||
// fontSize = defaultEdgeLabelSize if edgeLabelSizePowRatio = 1
|
||||
fontSize = (settings('edgeLabelSize') === 'fixed') ?
|
||||
settings('defaultEdgeLabelSize') :
|
||||
settings('defaultEdgeLabelSize') *
|
||||
size *
|
||||
Math.pow(size, -1 / settings('edgeLabelSizePowRatio'));
|
||||
|
||||
context.save();
|
||||
|
||||
|
||||
if (edge.active) {
|
||||
context.font = [
|
||||
settings('activeFontStyle'),
|
||||
fontSize + 'px',
|
||||
settings('activeFont') || settings('font')
|
||||
].join(' ');
|
||||
|
||||
context.fillStyle =
|
||||
settings('edgeActiveColor') === 'edge' ?
|
||||
(edge.active_color || settings('defaultEdgeActiveColor')) :
|
||||
settings('defaultEdgeLabelActiveColor');
|
||||
}
|
||||
else {
|
||||
context.font = [
|
||||
settings('fontStyle'),
|
||||
fontSize + 'px',
|
||||
settings('font')
|
||||
].join(' ');
|
||||
|
||||
context.fillStyle =
|
||||
(settings('edgeLabelColor') === 'edge') ?
|
||||
(edge.color || settings('defaultEdgeColor')) :
|
||||
settings('defaultEdgeLabelColor');
|
||||
}
|
||||
|
||||
context.textAlign = 'center';
|
||||
context.textBaseline = 'alphabetic';
|
||||
|
||||
context.translate(c.x, c.y);
|
||||
context.rotate(angle);
|
||||
context.fillText(
|
||||
edge.label,
|
||||
0,
|
||||
(-size / 2) - 3
|
||||
);
|
||||
|
||||
context.restore();
|
||||
};
|
||||
}).call(this);
|
|
@ -0,0 +1,25 @@
|
|||
;(function(undefined) {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined')
|
||||
throw 'sigma is not declared';
|
||||
|
||||
// Initialize packages:
|
||||
sigma.utils.pkg('sigma.canvas.edges.labels');
|
||||
|
||||
/**
|
||||
* This label renderer will just display the label on the curve of the edge.
|
||||
* The label is rendered at half distance of the edge extremities, and is
|
||||
* always oriented from left to right on the top side of the curve.
|
||||
*
|
||||
* @param {object} edge The edge object.
|
||||
* @param {object} source node The edge source node.
|
||||
* @param {object} target node The edge target node.
|
||||
* @param {CanvasRenderingContext2D} context The canvas context.
|
||||
* @param {configurable} settings The settings function.
|
||||
*/
|
||||
sigma.canvas.edges.labels.curvedArrow =
|
||||
function(edge, source, target, context, settings) {
|
||||
sigma.canvas.edges.labels.curve(edge, source, target, context, settings);
|
||||
};
|
||||
}).call(this);
|
|
@ -0,0 +1,96 @@
|
|||
;(function(undefined) {
|
||||
'use strict';
|
||||
|
||||
if (typeof sigma === 'undefined')
|
||||
throw 'sigma is not declared';
|
||||
|
||||
// Initialize packages:
|
||||
sigma.utils.pkg('sigma.canvas.edges.labels');
|
||||
|
||||
/**
|
||||
* This label renderer will just display the label on the line of the edge.
|
||||
* The label is rendered at half distance of the edge extremities, and is
|
||||
* always oriented from left to right on the top side of the line.
|
||||
*
|
||||
* @param {object} edge The edge object.
|
||||
* @param {object} source node The edge source node.
|
||||
* @param {object} target node The edge target node.
|
||||
* @param {CanvasRenderingContext2D} context The canvas context.
|
||||
* @param {configurable} settings The settings function.
|
||||
*/
|
||||
sigma.canvas.edges.labels.def =
|
||||
function(edge, source, target, context, settings) {
|
||||
if (typeof edge.label !== 'string' || source == target)
|
||||
return;
|
||||
|
||||
var prefix = settings('prefix') || '',
|
||||
size = edge[prefix + 'size'] || 1;
|
||||
|
||||
if (size < settings('edgeLabelThreshold'))
|
||||
return;
|
||||
|
||||
if (0 === settings('edgeLabelSizePowRatio'))
|
||||
throw '"edgeLabelSizePowRatio" must not be 0.';
|
||||
|
||||
var fontSize,
|
||||
x = (source[prefix + 'x'] + target[prefix + 'x']) / 2,
|
||||
y = (source[prefix + 'y'] + target[prefix + 'y']) / 2,
|
||||
dX = target[prefix + 'x'] - source[prefix + 'x'],
|
||||
dY = target[prefix + 'y'] - source[prefix + 'y'],
|
||||
sign = (source[prefix + 'x'] < target[prefix + 'x']) ? 1 : -1,
|
||||
angle = Math.atan2(dY * sign, dX * sign);
|
||||
|
||||
// The font size is sublineraly proportional to the edge size, in order to
|
||||
// avoid very large labels on screen.
|
||||
// This is achieved by f(x) = x * x^(-1/ a), where 'x' is the size and 'a'
|
||||
// is the edgeLabelSizePowRatio. Notice that f(1) = 1.
|
||||
// The final form is:
|
||||
// f'(x) = b * x * x^(-1 / a), thus f'(1) = b. Application:
|
||||
// fontSize = defaultEdgeLabelSize if edgeLabelSizePowRatio = 1
|
||||
fontSize = (settings('edgeLabelSize') === 'fixed') ?
|
||||
settings('defaultEdgeLabelSize') :
|
||||
settings('defaultEdgeLabelSize') *
|
||||
size *
|
||||
Math.pow(size, -1 / settings('edgeLabelSizePowRatio'));
|
||||
|
||||
context.save();
|
||||
|
||||
if (edge.active) {
|
||||
context.font = [
|
||||
settings('activeFontStyle'),
|
||||
fontSize + 'px',
|
||||
settings('activeFont') || settings('font')
|
||||
].join(' ');
|
||||
|
||||
context.fillStyle =
|
||||
settings('edgeActiveColor') === 'edge' ?
|
||||
(edge.active_color || settings('defaultEdgeActiveColor')) :
|
||||
settings('defaultEdgeLabelActiveColor');
|
||||
}
|
||||
else {
|
||||
context.font = [
|
||||
settings('fontStyle'),
|
||||
fontSize + 'px',
|
||||
settings('font')
|
||||
].join(' ');
|
||||
|
||||
context.fillStyle =
|
||||
(settings('edgeLabelColor') === 'edge') ?
|
||||
(edge.color || settings('defaultEdgeColor')) :
|
||||
settings('defaultEdgeLabelColor');
|
||||
}
|
||||
|
||||
context.textAlign = 'center';
|
||||
context.textBaseline = 'alphabetic';
|
||||
|
||||
context.translate(x, y);
|
||||
context.rotate(angle);
|
||||
context.fillText(
|
||||
edge.label,
|
||||
0,
|
||||
(-size / 2) - 3
|
||||
);
|
||||
|
||||
context.restore();
|
||||
};
|
||||
}).call(this);
|
|
@ -0,0 +1,31 @@
|
|||
sigma.renderers.edgeLabels
|
||||
==================
|
||||
|
||||
Plugin developed by [Jack Miner](https://github.com/3ch01c).
|
||||
|
||||
Contact: 3ch01c@gmail.com
|
||||
|
||||
---
|
||||
## General
|
||||
This plugin allows visualizing multiple parallel edges.
|
||||
|
||||
See the following [example](../../examples/parallel-edges.html) for full usage.
|
||||
|
||||
To use it, include all .js files under this folder.
|
||||
|
||||
## Edges
|
||||
|
||||
This plugin extends Sigma.js edges:
|
||||
|
||||
* **count**
|
||||
* Represents the index of the edge in the set of parallel edges. Inversely proportional to the amplitude of the vertex of the edge curve.
|
||||
* type: *number*
|
||||
* default value: `0`
|
||||
|
||||
## Renderers
|
||||
|
||||
This plugin modifies
|
||||
|
||||
## Utils
|
||||
|
||||
This plugin modifies functions `sigma.utils.getQuadraticControlPoint` and `sigma.utils.getSelfLoopControlPoints` with an optional amplitude modifier parameters.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue