flow like the river

This commit is contained in:
root 2025-11-07 00:06:12 +01:00
commit 013fe673f3
42435 changed files with 5764238 additions and 0 deletions

View file

@ -0,0 +1,2 @@
> 1%
last 2 versions

View file

@ -0,0 +1,18 @@
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/essential',
'eslint:recommended'
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-unused-vars': 'off'
},
parserOptions: {
parser: 'babel-eslint'
}
}

33
VISUALIZACION/node_modules/ngraph.forcelayout/demo/README.md generated vendored Executable file
View file

@ -0,0 +1,33 @@
# ngraph.forcelayout demo
This folder contains a demo of the `ngraph.forcelayout` package.
If you drop any `.dot` file into the browser window the demo will attempt to visualize it.
### Compiles and hot-reloads for development
```
npm start
```
This should render a simple graph and you can do some basic layout. You can drop `.dot` files into it
to load new graphs.
### Compiles and minifies for production
```
npm run build
```
## What's inside?
* [ngraph.graph](https://github.com/anvaka/ngraph.graph) as a graph data structure
* [ngraph.forcelayout](https://github.com/anvaka/ngraph.forcelayout) for the basic graph layout
* [w-gl](https://github.com/anvaka/w-gl) - super duper obscure (and fast) WebGL renderer.
* vue.js powered UI and dev tools.
## Thanks!
* Stay tuned for updates: https://twitter.com/anvaka
* If you like my work and would like to support it - https://www.patreon.com/anvaka

View file

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

10
VISUALIZACION/node_modules/ngraph.forcelayout/demo/deploy.sh generated vendored Executable file
View file

@ -0,0 +1,10 @@
#!/bin/sh
rm -rf ./dist
npm run build
cd ./dist
git init
git add .
git commit -m 'push to gh-pages'
## Change the line below to deploy to your gh-pages
git push --force git@github.com:anvaka/ngraph.forcelayout.git master:gh-pages
cd ../

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,37 @@
{
"name": "graph-layout-demo",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"start": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.6.5",
"d3-color": "^2.0.0",
"miserables": "^2.0.0",
"ngraph.events": "^1.0.0",
"ngraph.forcelayout": "^3.2.0",
"ngraph.fromdot": "^6.0.0",
"ngraph.fromjson": "^3.0.0",
"ngraph.generators": "^20.0.0",
"ngraph.graph": "^20.0.0",
"ngraph.hde": "^1.0.1",
"query-state": "^4.3.0",
"vue": "^2.6.12",
"w-gl": "^0.19.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.5.4",
"@vue/cli-plugin-eslint": "^4.5.4",
"@vue/cli-service": "^4.5.4",
"babel-eslint": "^10.0.3",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"stylus": "^0.54.8",
"stylus-loader": "^3.0.2",
"vue-template-compiler": "^2.6.11"
}
}

View file

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>ngraph.forcelayout demo</title>
<!-- <script src="ngraph.forcelayout2d.js"></script> -->
<style>
* {
box-sizing: border-box;
}
body {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #EEE;
margin: 0;
background: rgb(12, 41, 82);
overflow: hidden;
}
canvas {
position: absolute;
width: 100%;
height: 100%;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
</style>
</head>
<body>
<noscript>
<strong>We're sorry but puller doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<canvas id='cnv'></canvas>
<div id="app"></div>
<!-- built files will be auto injected -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-47259320-1', 'anvaka.github.io');
ga('send', 'pageview');
</script>
</body>
</html>

View file

@ -0,0 +1,225 @@
<template>
<div id="app">
<h2><a href='https://github.com/anvaka/ngraph.forcelayout'>ngraph.forcelayout</a> demo
<small class='toggle-settings'><a href='#' @click.prevent='settingsOpen = !settingsOpen'>{{settingsOpen ? 'hide settings' : 'show settings'}}</a></small>
</h2>
<div class='content' v-if='settingsOpen'>
<div class='row'>
<div class='label'>Graph </div>
<select v-model='selectedGraph' :disable='loading' class='value'>
<option v-for="graph in graphs" :key='graph' :value='graph'>{{graph}}</option>
</select>
</div>
<input-value label='Time step' v-model='layoutSettings.timeStep'>
This is integration time step value. The higher it is, the faster nodes will move, but setting it too high
can result in lots of jitter and instability.
</input-value>
<input-value label='Gravity' v-model='layoutSettings.gravity'>
This coefficient defines how strongly each node repels each other.
</input-value>
<input-value label='Ideal spring length' v-model='layoutSettings.springLength'>
What is the ideal length of each spring?
</input-value>
<input-value label='Spring coefficient' v-model='layoutSettings.springCoefficient'>
Higher values makes the spring force stronger, pushing edges closer to the ideal spring length.
</input-value>
<input-value label='Drag coefficient' v-model='layoutSettings.dragCoefficient'>
This coefficient introduces "resistance" from environment. When it is close to 0 the forces
will have a lot of freedom, nothing will be stopping them, and that can result in a very
unstable simulation.
</input-value>
<input-value label='Theta' v-model='layoutSettings.theta'>
This coefficient influences when we apply long distance forces approximation. When this value is
close to 0, the simulation compares forces between every single node (giving O(n^2), slow performance).
Recommended value is 0.8.
</input-value>
<input-value label='Dimensions' v-model='layoutSettings.dimensions' step=1>
Defines number of dimensions of the space where layout is performed. For visualization purpose
2 or 3 dimensions are normally enough. Note: Memory consumptions grows exponentially with number
of dimensions.
</input-value>
<input-flag label='Follow bounding box' v-model='fixedViewBox' step=1>
Setting this to true will disable pan/zoom but will always keep the graph visible. This is not
part of the layout algorithm. Just a view setting of the renderer.
</input-flag>
<div v-if='loading'>Loading graph...</div>
</div>
<div v-if='!loading' class='layout-box'>
<a href="#" @click.prevent='toggleLayoutRun' class='btn'>{{isRunning ? 'Stop layout' : 'Start layout'}}</a>
</div>
</div>
</template>
<script>
import createGraphScene from './lib/createGraphScene';
import getAvailableGraphs from './lib/getAvailableGraphs';
import loadGraph from './lib/loadGraph';
import bus from './lib/bus';
import queryState from 'query-state';
import InputValue from './components/InputValue';
import InputFlag from './components/InputFlag';
let appState = queryState({
graph: 'Miserables',
timeStep: 0.5,
springLength: 10,
springCoefficient: 0.8,
dragCoefficient: 0.9,
dimensions: 2,
theta: 0.8,
gravity: -12,
}, { useSearch: true });
export default {
name: 'app',
components: {
InputValue,
InputFlag
},
methods: {
toggleLayoutRun() {
this.isRunning = !this.isRunning;
this.scene.runLayout(this.isRunning);
},
loadNewGraph(newGraph) {
this.loading = true;
this.stats = null;
this.isRunning = false;
loadGraph(newGraph).then(newGraph => {
bus.fire('load-graph', newGraph, this.selectedLayout);
this.loading = false;
});
},
onGraphLoaded() {
this.isRunning = false;
}
},
watch: {
layoutSettings: {
deep: true,
handler(newValue) {
this.scene.updateLayoutSettings(newValue);
appState.set(newValue);
}
},
fixedViewBox(newValue) {
this.scene.setFixedViewBox(newValue);
},
selectedGraph(newGraph) {
appState.set('graph', newGraph);
this.loadNewGraph(newGraph);
}
},
data() {
let graphs = getAvailableGraphs();
return {
isRunning: false,
fixedViewBox: false,
selectedGraph: appState.get('graph'),
settingsOpen: window.innerWidth > 500,
loading: false,
layoutSettings: {
timeStep: appState.get('timeStep'),
springLength: appState.get('springLength'),
springCoefficient: appState.get('springCoefficient'),
dragCoefficient: appState.get('dragCoefficient'),
dimensions: appState.get('dimensions'),
theta: appState.get('theta'),
gravity: appState.get('gravity'),
},
graphs
}
},
mounted() {
const canvas = document.getElementById('cnv');
this.scene = createGraphScene(canvas, {...this.layoutSettings});
this.loadNewGraph(this.selectedGraph);
bus.on('load-graph', this.onGraphLoaded);
},
beforeDestroy() {
if (this.scene) {
this.scene.dispose();
}
}
}
</script>
<style lang='stylus'>
small-screen = 500px;
#app {
position: absolute;
width: 400px;
background: rgb(12, 41, 82);
border: 1px solid white;
}
a {
text-decoration: none;
}
.content {
padding: 8px;
}
.row {
display: flex;
flex-direction: row;
align-items: baseline;
}
.row .label {
flex: 1;
}
.row .value {
flex: 1;
}
.row select {
width: 100%;
}
a.btn {
color: rgb(244, 244, 244);
text-decoration: none;
justify-content: center;
align-items: center;
border-top: 1px solid;
height: 32px;
width: 100%;
display: flex;
margin: 0;
}
h2 {
margin: 8px;
font-size: 18px;
font-weight: normal;
a {
color: #267fcd;
}
small a {
position: absolute;
right: 8px;
top: 8px;
font-size: 12px;
}
}
.number {
color: yellow;
font-size: 18px;
}
.names {
position: fixed;
font-size: 24px;
top: 18px;
left: 50%;
transform: translateX(-50%);
}
@media (max-width: small-screen) {
#app {
width: 100%;
}
}
</style>

View file

@ -0,0 +1,15 @@
<template>
<a @click.prevent='show' class='help-icon' href='#' title='Click for more details'>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="9" height="14" viewBox="0 0 9 14" fill='#267fcd' >
<path d="M5.5 9.812v1.875q0 0.125-0.094 0.219t-0.219 0.094h-1.875q-0.125 0-0.219-0.094t-0.094-0.219v-1.875q0-0.125 0.094-0.219t0.219-0.094h1.875q0.125 0 0.219 0.094t0.094 0.219zM7.969 5.125q0 0.422-0.121 0.789t-0.273 0.598-0.43 0.465-0.449 0.34-0.477 0.277q-0.32 0.18-0.535 0.508t-0.215 0.523q0 0.133-0.094 0.254t-0.219 0.121h-1.875q-0.117 0-0.199-0.145t-0.082-0.293v-0.352q0-0.648 0.508-1.223t1.117-0.848q0.461-0.211 0.656-0.438t0.195-0.594q0-0.328-0.363-0.578t-0.84-0.25q-0.508 0-0.844 0.227-0.273 0.195-0.836 0.898-0.102 0.125-0.242 0.125-0.094 0-0.195-0.062l-1.281-0.977q-0.102-0.078-0.121-0.195t0.043-0.219q1.25-2.078 3.625-2.078 0.625 0 1.258 0.242t1.141 0.648 0.828 0.996 0.32 1.238z"></path>
</svg>
</a>
</template>
<script>
export default {
methods: {
show() { this.$emit('show');}
}
}
</script>

View file

@ -0,0 +1,102 @@
<template>
<div class='block'>
<div class='row'>
<div class='col'>{{label}}</div>
<div class='col'>
<input type='checkbox' v-model='inputValue' >
</div>
<help-icon @show='helpVisible = !helpVisible' :class='{open: helpVisible}'></help-icon>
</div>
<div class='row help' v-if='helpVisible'>
<slot></slot>
</div>
</div>
</template>
<script>
import HelpIcon from './HelpIcon';
export default {
components: {
HelpIcon
},
props: {
label: String,
value: Boolean,
},
methods: {
selectAll(e) {
e.target.select()
}
},
data() {
return {
helpVisible: false,
inputValue: this.value
}
},
watch: {
inputValue(newValue) {
this.$emit('input', newValue);
}
}
}
</script>
<style lang="stylus">
primary-text = white;
help-background = #004499;
.block {
.row {
display: flex;
flex-direction: row;
margin-top: 1px;
}
.col {
flex: 1;
}
a.help-icon {
display: flex;
align-items: center;
justify-content: center;
align-self: stretch;
width: 25px;
margin-right: -7px;
svg {
fill: secondary-text;
}
&.open {
background: help-background;
svg {
fill: primary-text;
}
}
}
.row.help {
margin-top: 0;
background: help-background;
padding: 8px;
margin: 0 -7px;
}
input[type='text'],
input[type='number'] {
background: transparent;
color: primary-text;
border: 1px solid transparent;
padding: 7px;
font-size: 16px;
width: 100%;
margin-left: 7px;
&:focus {
outline-offset: 0;
outline: none;
border: 1px dashed;
background: #13294f;
}
&:invalid {
box-shadow:none;
}
}
}
</style>

View file

@ -0,0 +1,113 @@
<template>
<div class='block'>
<div class='row'>
<div class='col'>{{label}}</div>
<div class='col'>
<input type='number'
:step='step'
v-model='inputValue'
@focus="selectAll"
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false">
</div>
<help-icon @show='helpVisible = !helpVisible' :class='{open: helpVisible}'></help-icon>
</div>
<div class='row help' v-if='helpVisible'>
<slot></slot>
</div>
</div>
</template>
<script>
import HelpIcon from './HelpIcon';
export default {
components: {
HelpIcon
},
props: {
label: String,
value: Number,
step: {
default: '0.1',
type: String
},
},
methods: {
selectAll(e) {
e.target.select()
}
},
data() {
return {
helpVisible: false,
inputValue: this.value
}
},
watch: {
inputValue(newValue) {
this.$emit('input', parseFloat(newValue));
}
}
}
</script>
<style lang="stylus">
primary-text = white;
help-background = #004499;
.block {
.row {
display: flex;
flex-direction: row;
margin-top: 1px;
}
.col {
flex: 1;
}
a.help-icon {
display: flex;
align-items: center;
justify-content: center;
align-self: stretch;
width: 25px;
margin-right: -7px;
svg {
fill: secondary-text;
}
&.open {
background: help-background;
svg {
fill: primary-text;
}
}
}
.row.help {
margin-top: 0;
background: help-background;
padding: 8px;
margin: 0 -7px;
}
input[type='text'],
input[type='number'] {
background: transparent;
color: primary-text;
border: 1px solid transparent;
padding: 7px;
font-size: 16px;
width: 100%;
margin-left: 7px;
&:focus {
outline-offset: 0;
outline: none;
border: 1px dashed;
background: #13294f;
}
&:invalid {
box-shadow:none;
}
}
}
</style>

View file

@ -0,0 +1,98 @@
import {GLCollection, defineProgram, InstancedAttribute, ColorAttribute} from 'w-gl';
export default class LineCollection extends GLCollection {
constructor(gl, options = {}) {
let program = defineProgram({
gl,
vertex: `
uniform mat4 modelViewProjection;
uniform float width;
uniform vec2 resolution;
attribute vec4 color;
attribute vec3 from, to;
attribute vec2 point;
varying vec4 vColor;
varying vec2 vPoint;
void main() {
vec4 clip0 = modelViewProjection * vec4(from, 1.0);
vec4 clip1 = modelViewProjection * vec4(to, 1.0);
vec2 screen0 = resolution * (0.5 * clip0.xy/clip0.w + 0.5);
vec2 screen1 = resolution * (0.5 * clip1.xy/clip1.w + 0.5);
vec2 xBasis = normalize(screen1 - screen0);
vec2 yBasis = vec2(-xBasis.y, xBasis.x);
// Offset the original points:
vec2 pt0 = screen0 + width * point.x * yBasis;
vec2 pt1 = screen1 + width * point.x * yBasis;
vec2 pt = mix(pt0, pt1, point.y);
vec4 clip = mix(clip0, clip1, point.y);
gl_Position = vec4(clip.w * (2.0 * pt/resolution - 1.0), clip.z, clip.w);
vColor = color.abgr; // mix(.abgr, aToColor.abgr, aPosition.y);
}`,
fragment: `
precision highp float;
varying vec4 vColor;
void main() {
gl_FragColor = vColor;
}`,
attributes: {
color: new ColorAttribute()
},
instanced: {
point: new InstancedAttribute([
-0.5, 0, -0.5, 1, 0.5, 1, // First 2D triangle of the quad
-0.5, 0, 0.5, 1, 0.5, 0 // Second 2D triangle of the quad
])
}
});
super(program);
this.width = options.width || 2;
}
draw(_, drawContext) {
if (!this.uniforms) {
this.uniforms = {
modelViewProjection: this.modelViewProjection,
width: this.width,
resolution: [drawContext.width, drawContext.height]
}
}
this.uniforms.resolution[0] = drawContext.width;
this.uniforms.resolution[1] = drawContext.height;
this.program.draw(this.uniforms);
}
// implement lineRenderTrait to allow SVG export via w-gl
forEachLine(cb) {
let count = this.program.getCount()
for (let i = 0; i < count; ++i) {
let vertex = this.program.get(i);
let from = { x: vertex.from[0], y: vertex.from[1], z: vertex.from[2], color: vertex.color }
let to = { x: vertex.to[0], y: vertex.to[1], z: vertex.to[2], color: vertex.color }
cb(from, to);
}
}
getLineColor(from) {
let count = this.program.getCount()
let c = from ?
from.color :
count > 0 ? this.program.get(0).color : 0xFFFFFFFF;
return [
(c >> 24) & 0xFF / 255,
(c >> 16) & 0xFF / 255,
(c >> 8) & 0xFF / 255,
(c >> 0) & 0xFF / 255,
]
}
}

View file

@ -0,0 +1,56 @@
import {GLCollection, defineProgram, ColorAttribute, InstancedAttribute} from 'w-gl';
export default class PointCollection extends GLCollection {
constructor(gl) {
let program = defineProgram({
gl,
vertex: `
uniform mat4 modelViewProjection;
attribute float size;
attribute vec3 position;
attribute vec4 color;
attribute vec2 point; // instanced
varying vec4 vColor;
varying vec2 vPoint;
void main() {
gl_Position = modelViewProjection * vec4(position + vec3(point * size, 0.), 1.0);
vColor = color.abgr;
vPoint = point;
}`,
fragment: `
precision highp float;
varying vec4 vColor;
varying vec2 vPoint;
void main() {
float dist = length(vPoint);
if (dist >= 0.5) {discard;}
gl_FragColor = vColor;
}`,
// These are just overrides:
attributes: {
color: new ColorAttribute(),
},
instanced: {
point: new InstancedAttribute([
-0.5, -0.5, -0.5, 0.5, 0.5, 0.5,
0.5, 0.5, 0.5, -0.5, -0.5, -0.5,
])
},
preDrawHook(/* programInfo */) {
return `gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);`;
},
postDrawHook() {
return 'gl.disable(gl.DEPTH_TEST);';
},
});
super(program);
}
}

View file

@ -0,0 +1,5 @@
import eventify from 'ngraph.events';
const bus = eventify({});
export default bus;

View file

@ -0,0 +1,15 @@
import createLayout from '../../../';
export default function createForceLayout(graph, layoutSettings) {
// return window.ngraphCreate2dLayout(graph, Object.assign({
return createLayout(graph, Object.assign({
dimensions: 2,
timeStep: 0.5,
springLength: 10,
gravity: -12,
springCoefficient: 0.8,
dragCoefficient: 0.9,
// adaptiveTimeStepWeight: 0.1,
debug: false,
}, layoutSettings));
}

View file

@ -0,0 +1,259 @@
import {createScene, createGuide} from 'w-gl';
import LineCollection from './LineCollection';
import PointCollection from './PointCollection';
import bus from './bus';
import createHighLayout from 'ngraph.hde'
import createForceLayout from './createForceLayout';
import findLargestComponent from './findLargestComponent';
import createGraph from 'ngraph.graph';
export default function createGraphScene(canvas, layoutSettings = {}) {
let drawLinks = true;
// Since graph can be loaded dynamically, we have these uninitialized
// and captured into closure. loadGraph will do the initialization
let graph, layout;
let scene, nodes, lines, guide;
let fixedViewBox = false;
let isRunning = false;
let rafHandle;
bus.on('load-graph', loadGraph);
return {
dispose,
runLayout,
updateLayoutSettings,
setFixedViewBox,
};
function loadGraph(newGraph, desiredLayout) {
if (scene) {
scene.dispose();
layout.dispose();
scene = null
isRunning = false;
cancelAnimationFrame(rafHandle);
}
// newGraph = createGraph(); newGraph.addLink(1, 2)
scene = initScene();
graph = newGraph; //findLargestComponent(newGraph, 1)[0];
// Let them play on console with it!
window.graph = graph;
guide = createGuide(scene, {showGrid: true, lineColor: 0xffffff10, maxAlpha: 0x10, showCursor: false});
// this is a standard force layout
layout = createForceLayout(graph, layoutSettings);
//standardizePositions(layout)
let minX = -42, minY = -42;
let maxX = 42, maxY =42
setSceneSize(Math.max(maxX - minX, maxY - minY) * 1.2);
initUIElements();
rafHandle = requestAnimationFrame(frame);
}
function setSceneSize(sceneSize) {
scene.setViewBox({
left: -sceneSize,
top: -sceneSize,
right: sceneSize,
bottom: sceneSize,
});
}
function runLayout(newIsRunning) {
isRunning = newIsRunning;
}
function updateLayoutSettings(newLayoutSettings) {
let props = ['timeStep', 'springLength', 'springCoefficient', 'dimensions', 'dragCoefficient', 'gravity', 'theta']
let previousDimensions = (layoutSettings && layoutSettings.dimensions) || 2;
layoutSettings = props.reduce((settings, name) => (settings[name] = newLayoutSettings[name], settings), {});
if (!layout) return;
if (layoutSettings.dimensions !== previousDimensions) {
let prevLayout = layout;
layout = createForceLayout(graph, layoutSettings)
graph.forEachNode(node => {
let prevPos = prevLayout.getNodePosition(node.id);
let positions = Object.keys(prevPos).map(name => prevPos[name]);
for (let i = previousDimensions; i < layoutSettings.dimensions; ++i) {
// If new layout has more dimensions than the previous layout, fill those with random values:
positions.push(Math.random());
}
positions.unshift(node.id);
layout.setNodePosition.apply(layout, positions);
});
prevLayout.dispose();
} else {
props.forEach(name => {
layout.simulator[name](layoutSettings[name]);
});
}
}
function setFixedViewBox(isFixed) {
fixedViewBox = isFixed;
}
function initScene() {
let scene = createScene(canvas);
scene.setClearColor(12/255, 41/255, 82/255, 1)
return scene;
}
function initUIElements() {
nodes = new PointCollection(scene.getGL(), {
capacity: graph.getNodesCount()
});
graph.forEachNode(node => {
var point = layout.getNodePosition(node.id);
let size = 1;
if (node.data && node.data.size) {
size = node.data.size;
} else {
if (!node.data) node.data = {};
node.data.size = size;
}
node.ui = {size, position: [point.x, point.y, point.z || 0], color: 0x90f8fcff};
node.uiId = nodes.add(node.ui);
});
lines = new LineCollection(scene.getGL(), { capacity: graph.getLinksCount() });
graph.forEachLink(link => {
var from = layout.getNodePosition(link.fromId);
var to = layout.getNodePosition(link.toId);
var line = { from: [from.x, from.y, from.z || 0], to: [to.x, to.y, to.z || 0], color: 0xFFFFFF10 };
link.ui = line;
link.uiId = lines.add(link.ui);
});
// lines.add({from: [0, 0, 0], to: [0, 10, 0], color: 0xFF0000FF})
scene.appendChild(lines);
scene.appendChild(nodes);
}
function frame() {
rafHandle = requestAnimationFrame(frame);
if (isRunning) {
layout.step();
if (fixedViewBox) {
let rect = layout.getGraphRect();
scene.setViewBox({
left: rect.min_x,
top: rect.min_y,
right: rect.max_x,
bottom: rect.max_y,
});
}
}
drawGraph();
scene.renderFrame();
}
function drawGraph() {
let names = ['x', 'y', 'z']
// let minR = Infinity; let maxR = -minR;
// let minG = Infinity; let maxG = -minG;
// let minB = Infinity; let maxB = -minB;
// graph.forEachNode(node => {
// let pos = layout.getNodePosition(node.id);
// if (pos.c4 < minR) minR = pos.c4;
// if (pos.c4 > maxR) maxR = pos.c4;
// if (pos.c5 < minG) minG = pos.c5;
// if (pos.c5 > maxG) maxG = pos.c5;
// if (pos.c6 < minB) minB = pos.c6;
// if (pos.c6 > maxB) maxB = pos.c6;
// });
graph.forEachNode(node => {
let pos = layout.getNodePosition(node.id);
let uiPosition = node.ui.position;
for (let i = 0; i < 3; ++i) {
uiPosition[i] = pos[names[i]] || 0;
}
// let r = Math.floor(255 * (pos.c4 - minR) / (maxR - minR)) << 24;
// let g = Math.floor(255 * (pos.c5 - minG) / (maxG - minG)) << 16;
// let b = Math.floor(255 * (pos.c6 - minB) / (maxB - minB)) << 8;
// [r, g, b] = lab2rgb(
// (pos.c4 - minR) / (maxR - minR),
// (pos.c5 - minG) / (maxG - minG),
// (pos.c6 - minB) / (maxB - minB)
// );
// node.ui.color = (0x000000FF | r | g | b);
nodes.update(node.uiId, node.ui)
});
if (drawLinks) {
graph.forEachLink(link => {
var fromPos = layout.getNodePosition(link.fromId);
var toPos = layout.getNodePosition(link.toId);
let {from, to} = link.ui;
for (let i = 0; i < 3; ++i) {
from[i] = fromPos[names[i]] || 0;
to[i] = toPos[names[i]] || 0;
}
// from[0] = fromPos.x || 0; from[1] = fromPos.y || 0; from[2] = fromPos.z || 0;
// to[0] = toPos.x || 0; to[1] = toPos.y || 0; to[2] = toPos.z || 0;
// link.ui.color = lerp(graph.getNode(link.fromId).ui.color, graph.getNode(link.toId).ui.color);
lines.update(link.uiId, link.ui);
})
}
}
function lerp(aColor, bColor) {
let ar = (aColor >> 24) & 0xFF;
let ag = (aColor >> 16) & 0xFF;
let ab = (aColor >> 8) & 0xFF;
let br = (bColor >> 24) & 0xFF;
let bg = (bColor >> 16) & 0xFF;
let bb = (bColor >> 8) & 0xFF;
let r = Math.floor((ar + br) / 2);
let g = Math.floor((ag + bg) / 2);
let b = Math.floor((ab + bb) / 2);
return (r << 24) | (g << 16) | (b << 8) | 0xF0;
}
function dispose() {
cancelAnimationFrame(rafHandle);
scene.dispose();
bus.off('load-graph', loadGraph);
}
}
function standardizePositions(layout) {
let arr = [];
let avgX = 0, avgY = 0;
layout.forEachBody(body => {
arr.push(body.pos);
avgX += body.pos.x;
avgY += body.pos.y;
});
let meanX = avgX / arr.length;
let meanY = avgY / arr.length;
let varX = 0, varY = 0;
arr.forEach(pos => {
varX += Math.pow(pos.x - meanX, 2);
varY += Math.pow(pos.y - meanY, 2);
});
varX = Math.sqrt(varX / arr.length);
varY = Math.sqrt(varY / arr.length);
arr.forEach(pos => {
pos.x = 10 * (pos.x - meanX) / varX;
pos.y = 10 * (pos.y - meanY) / varY;
});
}

View file

@ -0,0 +1,78 @@
/**
* Handles dropped files into the browser.
*/
export default function fileDrop(dropHandler, onDropped) {
dropHandler.addEventListener('drop', handleDrop, true);
dropHandler.addEventListener('dragover', handleDragOver);
dropHandler.addEventListener('dragenter', prevent);
dropHandler.addEventListener('dragleave', handleDragEnd)
dropHandler.addEventListener('dragend', handleDragEnd);
return {
dispose
}
function dispose() {
dropHandler.removeEventListener('drop', handleDrop);
dropHandler.removeEventListener('dragover', handleDragOver);
dropHandler.removeEventListener('dragenter', prevent);
dropHandler.removeEventListener('dragleave', handleDragEnd)
dropHandler.removeEventListener('dragend', handleDragEnd);
}
function prevent(e) {
if (!hasFiles(e)) return;
e.preventDefault();
}
function handleDrop(ev) {
handleDragEnd();
ev.preventDefault();
// If dropped items aren't files, reject them
var dt = ev.dataTransfer;
var files = []
var i, file;
if (dt.items) {
// Use DataTransferItemList interface to access the file(s)
for (i = 0; i < dt.items.length; i++) {
if (dt.items[i].kind == "file") {
file = dt.items[i].getAsFile();
files.push(file);
}
}
} else {
// Use DataTransfer interface to access the file(s)
for (i = 0; i < dt.files.length; i++) {
file = dt.files[i];
files.push(file);
}
}
onDropped(files);
}
function handleDragOver(e) {
if (!hasFiles(e)) return;
e.preventDefault();
dropHandler.classList.add('drag-over');
}
function hasFiles(e) {
if (!e.dataTransfer) return false;
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) return true;
var items = e.dataTransfer.items;
if (!items) return false;
for (var i = 0; i < items.length; ++i) {
if (items[i].kind === 'file') return true;
}
return false;
}
function handleDragEnd() {
dropHandler.classList.remove('drag-over');
}
}

View file

@ -0,0 +1,64 @@
import createGraph from 'ngraph.graph';
/**
* Returns array of first `count` largest connected components
* of the `graph`
*/
export default function findLargestComponent(graph, count) {
var nodeIdToComponentId = new Map();
var connectedComponents = [];
var lastComponentId = 0;
graph.forEachNode(function(node) {
if (nodeIdToComponentId.has(node.id)) {
// we already seen this cluster. Ignore it.
return;
}
// We found a new connected component:
nodeIdToComponentId.set(node.id, lastComponentId);
var currentComponent = new Set();
connectedComponents.push(currentComponent);
// Let's find what other nodes belong to this component
bfs(graph, node.id, otherNode => {
currentComponent.add(otherNode);
nodeIdToComponentId.set(otherNode, lastComponentId);
});
lastComponentId += 1;
});
return connectedComponents.sort((a, b) => b.size - a.size)
.slice(0, count)
.map(largestComponent => {
let subGraph = createGraph();
// not the most efficient way, as we iterate over every single link.
// This could be improved, for example by performing bfs from the component
graph.forEachLink(link => {
if (largestComponent.has(link.fromId)) {
subGraph.addLink(link.fromId, link.toId);
}
})
return subGraph;
});
}
function bfs(graph, startFromNodeId, visitor) {
let queue = [startFromNodeId];
let visited = new Set(queue);
while (queue.length) {
let nodeId = queue.shift();
visitor(nodeId);
graph.forEachLinkedNode(nodeId, function(otherNode) {
if (visited.has(otherNode.id)) return;
queue.push(otherNode.id);
visited.add(otherNode.id);
});
}
}

View file

@ -0,0 +1,731 @@
export default function getAvailableGraphs() {
return [
'Miserables',
'Binary',
'HB/blckhole',
'Bai/rw5151',
'HB/bcsstm13',
'HB/lshp1882',
'HB/plat1919',
'HB/bcsstk26',
'Bai/dw256A',
'Bai/tols2000',
'Bai/dw1024',
'Bai/rdb2048',
'Pajek/CSphd',
'GHS_indef/laser',
"Bai/bfwa398",
"Bai/bfwa62",
"Bai/bfwb398",
"Bai/bfwb62",
"Bai/bfwb782",
"Bai/bwm200",
"Bai/cdde1",
"Bai/cdde2",
"Bai/cdde3",
"Bai/cdde4",
"Bai/cdde5",
"Bai/cdde6",
"Bai/ck104",
"Bai/ck400",
"Bai/ck656",
"Bai/dw256B",
"Bai/dwa512",
"Bai/dwb512",
"Bai/dwg961a",
"Bai/lop163",
"Bai/mhdb416",
"Bai/odepa400",
"Bai/olm100",
"Bai/olm1000",
"Bai/olm500",
"Bai/pde225",
"Bai/pde900",
"Bai/qh1484",
"Bai/qh768",
"Bai/qh882",
"Bai/rdb1250",
"Bai/rdb1250l",
"Bai/rdb200",
"Bai/rdb200l",
"Bai/rdb450",
"Bai/rdb450l",
"Bai/rdb800l",
"Bai/rdb968",
"Bai/rw136",
"Bai/rw496",
"Bai/tols1090",
"Bai/tols340",
"Bai/tols90",
"Bai/tub100",
"Bai/tub1000",
"Barabasi/NotreDame_yeast",
"Bates/Chem97ZtZ",
"FEMLAB/poisson2D",
"FEMLAB/problem1",
"FIDAP/ex1",
"FIDAP/ex5",
"Grund/b1_ss",
"Grund/d_ss",
"Grund/poli",
"Gset/G11",
"Gset/G12",
"Gset/G13",
"Gset/G14",
"Gset/G15",
"Gset/G16",
"Gset/G17",
"Gset/G18",
"Gset/G19",
"Gset/G20",
"Gset/G21",
"Gset/G32",
"Gset/G33",
"Gset/G34",
"Gset/G35",
"Gset/G36",
"Gset/G37",
"Gset/G38",
"Gset/G39",
"Gset/G40",
"Gset/G41",
"Gset/G42",
"Gset/G43",
"Gset/G44",
"Gset/G45",
"Gset/G46",
"Gset/G47",
"Gset/G48",
"Gset/G49",
"Gset/G50",
"Gset/G51",
"Gset/G52",
"Gset/G53",
"Gset/G54",
"Gset/G55",
"Gset/G57",
"Hamrle/Hamrle1",
"HB/1138_bus",
"HB/494_bus",
"HB/662_bus",
"HB/685_bus",
"HB/abb313",
"HB/arc130",
"HB/ash219",
"HB/ash292",
"HB/ash331",
"HB/ash608",
"HB/ash85",
"HB/ash958",
"HB/bcspwr01",
"HB/bcspwr02",
"HB/bcspwr03",
"HB/bcspwr04",
"HB/bcspwr05",
"HB/bcspwr06",
"HB/bcspwr07",
"HB/bcspwr08",
"HB/bcspwr09",
"HB/bcsstk01",
"HB/bcsstk02",
"HB/bcsstk03",
"HB/bcsstk04",
"HB/bcsstk05",
"HB/bcsstk06",
"HB/bcsstk07",
"HB/bcsstk19",
"HB/bcsstk20",
"HB/bcsstk22",
"HB/bcsstm01",
"HB/bcsstm02",
"HB/bcsstm03",
"HB/bcsstm04",
"HB/bcsstm05",
"HB/bcsstm06",
"HB/bcsstm07",
"HB/bcsstm08",
"HB/bcsstm09",
"HB/bcsstm11",
"HB/bcsstm19",
"HB/bcsstm20",
"HB/bcsstm21",
"HB/bcsstm22",
"HB/bcsstm23",
"HB/bcsstm24",
"HB/bcsstm26",
"HB/bp_0",
"HB/bp_1000",
"HB/bp_1200",
"HB/bp_1400",
"HB/bp_1600",
"HB/bp_200",
"HB/bp_400",
"HB/bp_600",
"HB/bp_800",
"HB/can_1054",
"HB/can_1072",
"HB/can_144",
"HB/can_161",
"HB/can_187",
"HB/can_229",
"HB/can_24",
"HB/can_256",
"HB/can_268",
"HB/can_292",
"HB/can_445",
"HB/can_61",
"HB/can_62",
"HB/can_634",
"HB/can_715",
"HB/can_73",
"HB/can_838",
"HB/can_96",
"HB/curtis54",
"HB/dwt_1005",
"HB/dwt_1007",
"HB/dwt_1242",
"HB/dwt_162",
"HB/dwt_193",
"HB/dwt_198",
"HB/dwt_209",
"HB/dwt_221",
"HB/dwt_234",
"HB/dwt_245",
"HB/dwt_2680",
"HB/dwt_307",
"HB/dwt_310",
"HB/dwt_346",
"HB/dwt_361",
"HB/dwt_419",
"HB/dwt_492",
"HB/dwt_503",
"HB/dwt_512",
"HB/dwt_59",
"HB/dwt_592",
"HB/dwt_607",
"HB/dwt_66",
"HB/dwt_72",
"HB/dwt_758",
"HB/dwt_869",
"HB/dwt_87",
"HB/dwt_878",
"HB/dwt_918",
"HB/dwt_992",
"HB/eris1176",
"HB/fs_183_1",
"HB/fs_183_3",
"HB/fs_183_4",
"HB/fs_183_6",
"HB/fs_541_1",
"HB/fs_541_2",
"HB/fs_541_3",
"HB/fs_541_4",
"HB/fs_680_1",
"HB/fs_680_2",
"HB/fs_680_3",
"HB/gent113",
"HB/gr_30_30",
"HB/gre_1107",
"HB/gre_115",
"HB/gre_185",
"HB/gre_216a",
"HB/gre_216b",
"HB/gre_343",
"HB/gre_512",
"HB/hor_131",
"HB/ibm32",
"HB/illc1033",
"HB/impcol_a",
"HB/impcol_b",
"HB/impcol_c",
"HB/impcol_d",
"HB/impcol_e",
"HB/jagmesh1",
"HB/jagmesh2",
"HB/jagmesh3",
"HB/jagmesh4",
"HB/jagmesh5",
"HB/jagmesh7",
"HB/jagmesh8",
"HB/jagmesh9",
"HB/jgl009",
"HB/jgl011",
"HB/jpwh_991",
"HB/lap_25",
"HB/lns_131",
"HB/lns_511",
"HB/lnsp_131",
"HB/lnsp_511",
"HB/lock_700",
"HB/lshp1009",
"HB/lshp1270",
"HB/lshp1561",
"HB/lshp2233",
"HB/lshp2614",
"HB/lshp3025",
"HB/lshp3466",
"HB/lshp_265",
"HB/lshp_406",
"HB/lshp_577",
"HB/lshp_778",
"HB/lund_a",
"HB/lund_b",
"HB/mcca",
"HB/nnc261",
"HB/nnc666",
"HB/nos1",
"HB/nos2",
"HB/nos4",
"HB/nos5",
"HB/nos6",
"HB/nos7",
"HB/orsirr_1",
"HB/orsirr_2",
"HB/plat362",
"HB/plskz362",
"HB/pores_1",
"HB/pores_3",
"HB/rgg010",
"HB/saylr1",
"HB/saylr3",
"HB/sherman1",
"HB/sherman4",
"HB/shl_0",
"HB/shl_200",
"HB/shl_400",
"HB/sstmodel",
"HB/steam1",
"HB/steam3",
"HB/str_0",
"HB/str_200",
"HB/str_400",
"HB/str_600",
"HB/well1033",
"HB/west0067",
"HB/west0132",
"HB/west0156",
"HB/west0167",
"HB/west0381",
"HB/west0479",
"HB/west0497",
"HB/west0655",
"HB/west0989",
"HB/west1505",
"HB/west2021",
"HB/will199",
"HB/will57",
"HB/wm1",
"HB/wm2",
"HB/wm3",
"HB/young1c",
"HB/young2c",
"HB/young3c",
"HB/young4c",
"JGD_BIBD/bibd_11_5",
"JGD_BIBD/bibd_12_4",
"JGD_BIBD/bibd_12_5",
"JGD_BIBD/bibd_15_3",
"JGD_BIBD/bibd_17_3",
"JGD_BIBD/bibd_17_4",
"JGD_BIBD/bibd_17_4b",
"JGD_BIBD/bibd_81_2",
"JGD_BIBD/bibd_9_3",
"JGD_BIBD/bibd_9_5",
"JGD_CAG/CAG_mat364",
"JGD_CAG/CAG_mat72",
"JGD_Forest/TF10",
"JGD_Forest/TF11",
"JGD_Forest/TF12",
"JGD_Forest/TF13",
"JGD_Franz/Franz1",
"JGD_Franz/Franz3",
"JGD_G5/IG5-10",
"JGD_G5/IG5-6",
"JGD_G5/IG5-7",
"JGD_G5/IG5-8",
"JGD_G5/IG5-9",
"JGD_GL6/GL6_D_10",
"JGD_GL6/GL6_D_6",
"JGD_GL6/GL6_D_7",
"JGD_GL6/GL6_D_8",
"JGD_GL6/GL6_D_9",
"JGD_GL7d/GL7d10",
"JGD_GL7d/GL7d11",
"JGD_GL7d/GL7d26",
"JGD_Homology/ch3-3-b1",
"JGD_Homology/ch3-3-b2",
"JGD_Homology/ch4-4-b1",
"JGD_Homology/ch4-4-b2",
"JGD_Homology/ch4-4-b3",
"JGD_Homology/ch5-5-b1",
"JGD_Homology/ch5-5-b2",
"JGD_Homology/ch5-5-b3",
"JGD_Homology/ch5-5-b4",
"JGD_Homology/ch6-6-b1",
"JGD_Homology/ch6-6-b2",
"JGD_Homology/ch6-6-b5",
"JGD_Homology/ch7-6-b1",
"JGD_Homology/ch7-7-b1",
"JGD_Homology/ch7-8-b1",
"JGD_Homology/ch7-9-b1",
"JGD_Homology/ch8-8-b1",
"JGD_Homology/cis-n4c6-b1",
"JGD_Homology/cis-n4c6-b15",
"JGD_Homology/cis-n4c6-b2",
"JGD_Homology/klein-b1",
"JGD_Homology/klein-b2",
"JGD_Homology/mk10-b1",
"JGD_Homology/mk10-b2",
"JGD_Homology/mk10-b4",
"JGD_Homology/mk11-b1",
"JGD_Homology/mk12-b1",
"JGD_Homology/mk9-b1",
"JGD_Homology/mk9-b2",
"JGD_Homology/mk9-b3",
"JGD_Homology/n2c6-b1",
"JGD_Homology/n2c6-b10",
"JGD_Homology/n2c6-b2",
"JGD_Homology/n2c6-b3",
"JGD_Homology/n2c6-b9",
"JGD_Homology/n3c4-b1",
"JGD_Homology/n3c4-b2",
"JGD_Homology/n3c4-b3",
"JGD_Homology/n3c4-b4",
"JGD_Homology/n3c5-b1",
"JGD_Homology/n3c5-b2",
"JGD_Homology/n3c5-b3",
"JGD_Homology/n3c5-b4",
"JGD_Homology/n3c5-b5",
"JGD_Homology/n3c5-b6",
"JGD_Homology/n3c5-b7",
"JGD_Homology/n3c6-b1",
"JGD_Homology/n3c6-b10",
"JGD_Homology/n3c6-b11",
"JGD_Homology/n3c6-b2",
"JGD_Homology/n3c6-b3",
"JGD_Homology/n4c5-b1",
"JGD_Homology/n4c5-b10",
"JGD_Homology/n4c5-b11",
"JGD_Homology/n4c5-b2",
"JGD_Homology/n4c5-b3",
"JGD_Homology/n4c5-b9",
"JGD_Homology/n4c6-b1",
"JGD_Homology/n4c6-b15",
"JGD_Homology/n4c6-b2",
"JGD_Kocay/Trec10",
"JGD_Kocay/Trec3",
"JGD_Kocay/Trec4",
"JGD_Kocay/Trec5",
"JGD_Kocay/Trec6",
"JGD_Kocay/Trec7",
"JGD_Kocay/Trec8",
"JGD_Kocay/Trec9",
"JGD_Margulies/cat_ears_2_1",
"JGD_Margulies/cat_ears_2_4",
"JGD_Margulies/cat_ears_3_1",
"JGD_Margulies/cat_ears_4_1",
"JGD_Margulies/flower_4_1",
"JGD_Margulies/flower_5_1",
"JGD_Margulies/flower_7_1",
"JGD_Margulies/flower_8_1",
"JGD_Margulies/kneser_6_2_1",
"JGD_Margulies/wheel_3_1",
"JGD_Margulies/wheel_4_1",
"JGD_Margulies/wheel_5_1",
"JGD_Margulies/wheel_6_1",
"JGD_Margulies/wheel_7_1",
"JGD_Relat/rel3",
"JGD_Relat/rel4",
"JGD_Relat/rel5",
"JGD_Relat/rel6",
"JGD_Relat/relat3",
"JGD_Relat/relat4",
"JGD_Relat/relat5",
"JGD_Relat/relat6",
"JGD_SL6/D_10",
"JGD_SL6/D_11",
"JGD_SL6/D_5",
"JGD_SL6/D_6",
"JGD_SPG/08blocks",
"JGD_SPG/EX1",
"JGD_SPG/EX2",
"JGD_Trefethen/Trefethen_150",
"JGD_Trefethen/Trefethen_20",
"JGD_Trefethen/Trefethen_200",
"JGD_Trefethen/Trefethen_200b",
"JGD_Trefethen/Trefethen_20b",
"JGD_Trefethen/Trefethen_300",
"JGD_Trefethen/Trefethen_500",
"JGD_Trefethen/Trefethen_700",
"LPnetlib/lp_adlittle",
"LPnetlib/lp_afiro",
"LPnetlib/lp_agg",
"LPnetlib/lp_agg2",
"LPnetlib/lp_agg3",
"LPnetlib/lp_bandm",
"LPnetlib/lp_beaconfd",
"LPnetlib/lp_blend",
"LPnetlib/lp_bnl1",
"LPnetlib/lp_bore3d",
"LPnetlib/lp_brandy",
"LPnetlib/lp_capri",
"LPnetlib/lp_czprob",
"LPnetlib/lp_degen2",
"LPnetlib/lp_e226",
"LPnetlib/lp_etamacro",
"LPnetlib/lp_fffff800",
"LPnetlib/lp_finnis",
"LPnetlib/lp_fit1p",
"LPnetlib/lp_ganges",
"LPnetlib/lp_gfrd_pnc",
"LPnetlib/lp_grow15",
"LPnetlib/lp_grow7",
"LPnetlib/lp_israel",
"LPnetlib/lp_kb2",
"LPnetlib/lp_ken_07",
"LPnetlib/lp_lotfi",
"LPnetlib/lp_modszk1",
"LPnetlib/lp_perold",
"LPnetlib/lp_pilot4",
"LPnetlib/lp_qap8",
"LPnetlib/lp_recipe",
"LPnetlib/lp_sc105",
"LPnetlib/lp_sc205",
"LPnetlib/lp_sc50a",
"LPnetlib/lp_sc50b",
"LPnetlib/lp_scagr25",
"LPnetlib/lp_scagr7",
"LPnetlib/lp_scfxm1",
"LPnetlib/lp_scfxm2",
"LPnetlib/lp_scfxm3",
"LPnetlib/lp_scorpion",
"LPnetlib/lp_scrs8",
"LPnetlib/lp_scsd1",
"LPnetlib/lp_scsd6",
"LPnetlib/lp_sctap1",
"LPnetlib/lp_sctap2",
"LPnetlib/lp_sctap3",
"LPnetlib/lp_share1b",
"LPnetlib/lp_share2b",
"LPnetlib/lp_shell",
"LPnetlib/lp_ship04l",
"LPnetlib/lp_ship04s",
"LPnetlib/lp_ship08s",
"LPnetlib/lp_ship12s",
"LPnetlib/lp_sierra",
"LPnetlib/lp_stair",
"LPnetlib/lp_standata",
"LPnetlib/lp_standgub",
"LPnetlib/lp_standmps",
"LPnetlib/lp_stocfor1",
"LPnetlib/lp_tuff",
"LPnetlib/lp_vtp_base",
"LPnetlib/lpi_bgdbg1",
"LPnetlib/lpi_bgetam",
"LPnetlib/lpi_bgprtr",
"LPnetlib/lpi_box1",
"LPnetlib/lpi_chemcom",
"LPnetlib/lpi_cplex2",
"LPnetlib/lpi_ex72a",
"LPnetlib/lpi_ex73a",
"LPnetlib/lpi_forest6",
"LPnetlib/lpi_galenet",
"LPnetlib/lpi_itest2",
"LPnetlib/lpi_itest6",
"LPnetlib/lpi_klein1",
"LPnetlib/lpi_klein2",
"LPnetlib/lpi_mondou2",
"LPnetlib/lpi_pang",
"LPnetlib/lpi_pilot4i",
"LPnetlib/lpi_qual",
"LPnetlib/lpi_reactor",
"LPnetlib/lpi_refinery",
"LPnetlib/lpi_vol1",
"LPnetlib/lpi_woodinfe",
"MathWorks/Harvard500",
"MathWorks/Pd_rhs",
"MathWorks/pivtol",
"MathWorks/QRpivot",
"Meszaros/cep1",
"Meszaros/cr42",
"Meszaros/farm",
"Meszaros/gams10a",
"Meszaros/gams10am",
"Meszaros/gams30a",
"Meszaros/gams30am",
"Meszaros/gams60am",
"Meszaros/gas11",
"Meszaros/iiasa",
"Meszaros/iprob",
"Meszaros/kleemin",
"Meszaros/l9",
"Meszaros/model1",
"Meszaros/model2",
"Meszaros/nemsafm",
"Meszaros/nemscem",
"Meszaros/nsic",
"Meszaros/p0033",
"Meszaros/p0040",
"Meszaros/p0201",
"Meszaros/p0282",
"Meszaros/p0291",
"Meszaros/p0548",
"Meszaros/p2756",
"Meszaros/problem",
"Meszaros/qiulp",
"Meszaros/refine",
"Meszaros/rosen7",
"Meszaros/scagr7-2c",
"Meszaros/scrs8-2b",
"Meszaros/scrs8-2c",
"Meszaros/small",
"Meszaros/zed",
"Morandini/robot",
"Morandini/rotor1",
"Muite/Chebyshev1",
"NYPA/Maragal_1",
"NYPA/Maragal_2",
"Oberwolfach/LF10",
"Oberwolfach/LFAT5",
"Pajek/Cities",
"Pajek/divorce",
"Pajek/EPA",
"Pajek/Erdos02",
"Pajek/Erdos971",
"Pajek/Erdos972",
"Pajek/Erdos981",
"Pajek/Erdos982",
"Pajek/Erdos991",
"Pajek/Erdos992",
"Pajek/EVA",
"Pajek/football",
"Pajek/GD00_a",
"Pajek/GD00_c",
"Pajek/GD01_a",
"Pajek/GD01_A",
"Pajek/GD01_b",
"Pajek/GD01_c",
"Pajek/GD02_a",
"Pajek/GD02_b",
"Pajek/GD06_Java",
"Pajek/GD06_theory",
"Pajek/GD95_a",
"Pajek/GD95_b",
"Pajek/GD95_c",
"Pajek/GD96_a",
"Pajek/GD96_b",
"Pajek/GD96_c",
"Pajek/GD96_d",
"Pajek/GD97_a",
"Pajek/GD97_b",
"Pajek/GD97_c",
"Pajek/GD98_a",
"Pajek/GD98_b",
"Pajek/GD98_c",
"Pajek/GD99_b",
"Pajek/GD99_c",
"Pajek/GlossGT",
"Pajek/Journals",
"Pajek/Kohonen",
"Pajek/Ragusa16",
"Pajek/Ragusa18",
"Pajek/Roget",
"Pajek/Sandi_authors",
"Pajek/Sandi_sandi",
"Pajek/SciMet",
"Pajek/SmaGri",
"Pajek/SmallW",
"Pajek/Stranke94",
"Pajek/Tina_AskCal",
"Pajek/Tina_AskCog",
"Pajek/Tina_DisCal",
"Pajek/Tina_DisCog",
"Pajek/USAir97",
"Pajek/USpowerGrid",
"Pajek/WorldCities",
"Pajek/yeast",
"Pothen/mesh1e1",
"Pothen/mesh1em1",
"Pothen/mesh1em6",
"Pothen/mesh2e1",
"Pothen/mesh2em5",
"Pothen/mesh3e1",
"Pothen/mesh3em5",
"Pothen/sphere2",
"Pothen/sphere3",
"Qaplib/lp_nug05",
"Qaplib/lp_nug06",
"Qaplib/lp_nug07",
"Qaplib/lp_nug08",
"Rajat/rajat02",
"Rajat/rajat05",
"Rajat/rajat11",
"Rajat/rajat14",
"Rajat/rajat19",
"Sandia/oscil_dcop_01",
"Sandia/oscil_dcop_02",
"Sandia/oscil_dcop_03",
"Sandia/oscil_dcop_04",
"Sandia/oscil_dcop_05",
"Sandia/oscil_dcop_06",
"Sandia/oscil_dcop_07",
"Sandia/oscil_dcop_08",
"Sandia/oscil_dcop_09",
"Sandia/oscil_dcop_10",
"Sandia/oscil_dcop_11",
"Sandia/oscil_dcop_12",
"Sandia/oscil_dcop_13",
"Sandia/oscil_dcop_14",
"Sandia/oscil_dcop_15",
"Sandia/oscil_dcop_16",
"Sandia/oscil_dcop_17",
"Sandia/oscil_dcop_18",
"Sandia/oscil_dcop_19",
"Sandia/oscil_dcop_20",
"Sandia/oscil_dcop_21",
"Sandia/oscil_dcop_22",
"Sandia/oscil_dcop_23",
"Sandia/oscil_dcop_24",
"Sandia/oscil_dcop_25",
"Sandia/oscil_dcop_26",
"Sandia/oscil_dcop_27",
"Sandia/oscil_dcop_28",
"Sandia/oscil_dcop_29",
"Sandia/oscil_dcop_30",
"Sandia/oscil_dcop_31",
"Sandia/oscil_dcop_32",
"Sandia/oscil_dcop_33",
"Sandia/oscil_dcop_34",
"Sandia/oscil_dcop_35",
"Sandia/oscil_dcop_36",
"Sandia/oscil_dcop_37",
"Sandia/oscil_dcop_38",
"Sandia/oscil_dcop_39",
"Sandia/oscil_dcop_40",
"Sandia/oscil_dcop_41",
"Sandia/oscil_dcop_42",
"Sandia/oscil_dcop_43",
"Sandia/oscil_dcop_44",
"Sandia/oscil_dcop_45",
"Sandia/oscil_dcop_46",
"Sandia/oscil_dcop_47",
"Sandia/oscil_dcop_48",
"Sandia/oscil_dcop_49",
"Sandia/oscil_dcop_50",
"Sandia/oscil_dcop_51",
"Sandia/oscil_dcop_52",
"Sandia/oscil_dcop_53",
"Sandia/oscil_dcop_54",
"Sandia/oscil_dcop_55",
"Sandia/oscil_dcop_56",
"Sandia/oscil_dcop_57",
"Sandia/oscil_trans_01",
"TOKAMAK/utm300",
"vanHeukelum/cage3",
"vanHeukelum/cage4",
"vanHeukelum/cage5",
"vanHeukelum/cage6",
"vanHeukelum/cage7",
"YZhou/circuit204"
];
}

View file

@ -0,0 +1,24 @@
/**
* Load your graph here.
*/
// https://github.com/anvaka/miserables
import miserables from 'miserables';
// Other loaders:
// https://github.com/anvaka/ngraph.generators
// import generate from 'ngraph.generators';
// https://github.com/anvaka/ngraph.graph
// import createGraph from 'ngraph.graph';
// https://github.com/anvaka/ngraph.fromjson
// import fromjson from 'ngraph.fromjson'
// https://github.com/anvaka/ngraph.fromdot
// import fromdot from 'ngraph.fromdot'
export default function getGraph() {
return miserables.create();
// return generate.wattsStrogatz(20, 5, 0.4);
}

View file

@ -0,0 +1,39 @@
import fromDot from 'ngraph.fromdot';
import fromJson from 'ngraph.fromjson';
import bus from './bus.js';
/**
* Loads graph from a dropped file
*/
export default function loadDroppedGraph(files) {
let file = files[0];
var reader = new FileReader();
reader.readAsText(file, "UTF-8");
reader.onload = e => {
let content = e.target.result;
let graph = tryDot(content) || tryJson(content);
if (graph) bus.fire('load-graph', graph);
}
reader.onerror = (e) => {
//eslint-disable-next-line
console.log('error loading dot file: ', e)
};
function tryDot(fileContent) {
try {
return fromDot(fileContent);
} catch (e) {
//eslint-disable-next-line
console.log('error loading dot file: ', e)
}
}
function tryJson(fileContent) {
try {
return fromJson(JSON.parse(fileContent));
} catch (e) {
//eslint-disable-next-line
console.log('error loading JSON: ', e)
}
}
}

View file

@ -0,0 +1,54 @@
import createGraph from 'ngraph.graph';
import miserables from 'miserables';
import generate from 'ngraph.generators';
let cache = simpleCache();
export default function loadGraph(name) {
if (name === 'Miserables') return Promise.resolve(miserables);
if (name === 'Binary') return Promise.resolve(generate.balancedBinTree(10));
let mtxObject = cache.get(name);
if (mtxObject) return Promise.resolve(renderGraph(mtxObject.links, mtxObject.recordsPerEdge));
return fetch(`https://s3.amazonaws.com/yasiv_uf/out/${name}/index.js`, {
mode: 'cors'
})
.then(x => x.json())
.then(mtxObject => {
cache.put(name, mtxObject);
return renderGraph(mtxObject.links, mtxObject.recordsPerEdge);
});
}
function renderGraph (edges, recordsPerEdge) {
let graph = createGraph();
for(var i = 0; i < edges.length - 1; i += recordsPerEdge) {
graph.addLink(edges[i], edges[i + 1]);
}
return graph
}
function simpleCache() {
var supported = 'localStorage' in window;
return {
get : function(key) {
if (!supported) { return null; }
var graphData = JSON.parse(window.localStorage.getItem(key));
if (!graphData || graphData.recordsPerEdge === undefined) {
// this is old cache. Invalidate it
return null;
}
return graphData;
},
put : function(key, value) {
if (!supported) { return false;}
try {
window.localStorage.setItem(key, JSON.stringify(value));
} catch(err) {
// TODO: make something clever than this in case of quata exceeded.
window.localStorage.clear();
}
}
};
}

View file

@ -0,0 +1,54 @@
/**
* Set of function that I find useful for explorations.
*/
/**
* Performs hermit interpolation of `x` between two edges
*/
export function smoothStep(edge0, edge1, x) {
let t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
return t * t * (3.0 - 2.0 * t);
}
/**
* Clamp `x` to [min, max] range.
*/
export function clamp(x, min, max) {
return x < min ? min : x > max ? max : x;
}
/**
* Collects main statistical properties of a collection
*/
export function collectStatistics(array) {
if (array.length === 0) {
return {
min: undefined,
max: undefined,
avg: undefined,
sigma: undefined,
mod: undefined,
count: 0
}
}
let min = Infinity;
let max = -Infinity;
let sum = 0;
let counts = new Map();
array.forEach(x => {
if (x < min) min = x;
if (x > max) max = x;
sum += x;
counts.set(x, (counts.get(x) || 0) + 1)
});
let mod = Array.from(counts).sort((a, b) => b[1] - a[1])[0][0]
let avg = sum /= array.length;
let sigma = 0;
array.forEach(x => {
sigma += (x - avg) * (x - avg);
});
sigma = Math.sqrt(sigma / (array.length + 1));
let count = array.length;
return {min, max, avg, sigma, mod, count};
}

View file

@ -0,0 +1,13 @@
import Vue from 'vue'
import App from './App.vue'
import fileDrop from './lib/fileDrop.js';
import loadDroppedGraph from './lib/loadDroppedGraph.js';
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
// When they drop a `.dot` file into the browser - let's load it.
fileDrop(document.body, loadDroppedGraph);

View file

@ -0,0 +1,3 @@
module.exports = {
publicPath: ''
}