mirror of
https://gitee.com/antv/g6.git
synced 2024-12-02 03:38:20 +08:00
webworker pach problem
This commit is contained in:
parent
9a4951a752
commit
44289cd5dd
126
plugins/layout.forceAtlas2/BlobBuilder.js
Normal file
126
plugins/layout.forceAtlas2/BlobBuilder.js
Normal file
@ -0,0 +1,126 @@
|
||||
/* BlobBuilder.js
|
||||
* A complete BlobBuilder shim
|
||||
* By Eli Grey
|
||||
* License: MIT/X11
|
||||
*/
|
||||
|
||||
self.BlobBuilder || self.WebKitBlobBuilder || self.MozBlobBuilder || function (view) {
|
||||
"use strict";
|
||||
var
|
||||
get_class = function (object) {
|
||||
return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
|
||||
},
|
||||
FakeBlobBuilder = view.BlobBuilder = function () {},
|
||||
FakeBlob = view.Blob = function (data, type) {
|
||||
this.data = data;
|
||||
this.size = data.length;
|
||||
this.type = type;
|
||||
},
|
||||
FBB_proto = FakeBlobBuilder.prototype = [],
|
||||
FB_proto = FakeBlob.prototype,
|
||||
FileReaderSync = view.FileReaderSync,
|
||||
FileException = function (type) {
|
||||
this.code = this[this.name = type];
|
||||
},
|
||||
file_ex_codes = (
|
||||
"NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " +
|
||||
"NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
|
||||
).split(" "),
|
||||
file_ex_code = file_ex_codes.length,
|
||||
URL = view.URL = view.URL || view.webkitURL || view,
|
||||
real_create_object_url, real_revoke_object_url, btoa = view.btoa,
|
||||
ArrayBuffer = view.ArrayBuffer,
|
||||
can_apply_typed_arrays = false,
|
||||
can_apply_typed_arrays_test = function (pass) {
|
||||
can_apply_typed_arrays = !pass;
|
||||
};
|
||||
while (file_ex_code--) {
|
||||
FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
|
||||
}
|
||||
try {
|
||||
if (ArrayBuffer) {
|
||||
can_apply_typed_arrays_test.apply(0, new Uint8Array(1));
|
||||
}
|
||||
} catch (ex) {}
|
||||
if (!URL.createObjectURL) {
|
||||
URL = {};
|
||||
}
|
||||
real_create_object_url = URL.createObjectURL;
|
||||
real_revoke_object_url = URL.revokeObjectURL;
|
||||
URL.createObjectURL = function (blob) {
|
||||
var type = blob.type;
|
||||
if (type === null) {
|
||||
type = "application/octet-stream";
|
||||
}
|
||||
if (blob instanceof FakeBlob) {
|
||||
if (btoa) {
|
||||
return "data:" + type + ";base64," + btoa(blob.data);
|
||||
} else {
|
||||
return "data:" + type + "," + encodeURIComponent(blob.data);
|
||||
}
|
||||
} else if (real_create_object_url) {
|
||||
return real_create_object_url.call(URL, blob);
|
||||
}
|
||||
};
|
||||
URL.revokeObjectURL = function (object_url) {
|
||||
if (object_url.substring(0, 5) !== "data:" && real_revoke_object_url) {
|
||||
real_revoke_object_url.call(URL, object_url);
|
||||
}
|
||||
};
|
||||
FBB_proto.append = function (data /*, endings*/ ) {
|
||||
var bb = this;
|
||||
// decode data to a binary string
|
||||
if (ArrayBuffer && data instanceof ArrayBuffer) {
|
||||
if (can_apply_typed_arrays) {
|
||||
bb.push(String.fromCharCode.apply(String, new Uint8Array(data)));
|
||||
} else {
|
||||
var
|
||||
str = "",
|
||||
buf = new Uint8Array(data),
|
||||
i = 0,
|
||||
buf_len = buf.length;
|
||||
for (; i < buf_len; i++) {
|
||||
str += String.fromCharCode(buf[i]);
|
||||
}
|
||||
}
|
||||
} else if (get_class(data) === "Blob" || get_class(data) === "File") {
|
||||
if (FileReaderSync) {
|
||||
var fr = new FileReaderSync;
|
||||
bb.push(fr.readAsBinaryString(data));
|
||||
} else {
|
||||
// async FileReader won't work as BlobBuilder is sync
|
||||
throw new FileException("NOT_READABLE_ERR");
|
||||
}
|
||||
} else if (data instanceof FakeBlob) {
|
||||
bb.push(data.data);
|
||||
} else {
|
||||
if (typeof data !== "string") {
|
||||
data += ""; // convert unsupported types to strings
|
||||
}
|
||||
// decode UTF-16 to binary string
|
||||
bb.push(unescape(encodeURIComponent(data)));
|
||||
}
|
||||
};
|
||||
FBB_proto.getBlob = function (type) {
|
||||
if (!arguments.length) {
|
||||
type = null;
|
||||
}
|
||||
return new FakeBlob(this.join(""), type);
|
||||
};
|
||||
FBB_proto.toString = function () {
|
||||
return "[object BlobBuilder]";
|
||||
};
|
||||
FB_proto.slice = function (start, end, type) {
|
||||
var args = arguments.length;
|
||||
if (args < 3) {
|
||||
type = null;
|
||||
}
|
||||
return new FakeBlob(
|
||||
this.data.slice(start, args > 1 ? end : this.data.length), type
|
||||
);
|
||||
};
|
||||
FB_proto.toString = function () {
|
||||
return "[object Blob]";
|
||||
};
|
||||
return FakeBlobBuilder;
|
||||
}(self);
|
94
plugins/layout.forceAtlas2/body.js
Normal file
94
plugins/layout.forceAtlas2/body.js
Normal file
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* @fileOverview body
|
||||
* @author shiwu.wyy@antfin.com
|
||||
*/
|
||||
// represents a body(a point mass) and its position
|
||||
class Body {
|
||||
constructor(params) {
|
||||
/**
|
||||
* the id of this body, the same with the node id
|
||||
* @type {number}
|
||||
*/
|
||||
this.id = params.id;
|
||||
/**
|
||||
* the position of this body
|
||||
* @type {number}
|
||||
*/
|
||||
this.rx = params.rx;
|
||||
/**
|
||||
* the position of this body
|
||||
* @type {number}
|
||||
*/
|
||||
this.ry = params.ry;
|
||||
/**
|
||||
* the force acting on this body
|
||||
* @type {number}
|
||||
*/
|
||||
this.fx = 0;
|
||||
/**
|
||||
* the force acting on this body
|
||||
* @type {number}
|
||||
*/
|
||||
this.fy = 0;
|
||||
/**
|
||||
* the mass of this body, =1 for a node
|
||||
* @type {number}
|
||||
*/
|
||||
this.mass = params.mass;
|
||||
/**
|
||||
* the degree of the node represented by this body
|
||||
* @type {number}
|
||||
*/
|
||||
this.degree = params.degree;
|
||||
/**
|
||||
* the parameter for repulsive force, = kr
|
||||
* @type {number}
|
||||
*/
|
||||
this.G = params.G;
|
||||
}
|
||||
// returns the euclidean distance
|
||||
distanceTo(bo) {
|
||||
const dx = this.rx - bo.rx;
|
||||
const dy = this.ry - bo.ry;
|
||||
return Math.hypot(dx, dy);
|
||||
}
|
||||
setPos(x, y) {
|
||||
this.rx = x;
|
||||
this.ry = y;
|
||||
}
|
||||
// resets the forces
|
||||
resetForce() {
|
||||
this.fx = 0;
|
||||
this.fy = 0;
|
||||
}
|
||||
addForce(b) {
|
||||
const dx = b.rx - this.rx;
|
||||
const dy = b.ry - this.ry;
|
||||
let dist = Math.hypot(dx, dy);
|
||||
dist = dist < 0.0001 ? 0.0001 : dist;
|
||||
// the repulsive defined by force atlas 2
|
||||
const F = (this.G * (this.degree + 1) * (b.degree + 1)) / dist;
|
||||
this.fx += F * dx / dist;
|
||||
this.fy += F * dy / dist;
|
||||
}
|
||||
// if quad contains this body
|
||||
in(quad) {
|
||||
return quad.contains(this.rx, this.ry);
|
||||
}
|
||||
// returns a new body
|
||||
add(bo) {
|
||||
const nenw_mass = this.mass + bo.mass;
|
||||
const x = (this.rx * this.mass + bo.rx * bo.mass) / nenw_mass;
|
||||
const y = (this.ry * this.mass + bo.ry * bo.mass) / nenw_mass;
|
||||
const dg = this.degree + bo.degree;
|
||||
const params = {
|
||||
rx: x,
|
||||
ry: y,
|
||||
mass: nenw_mass,
|
||||
degree: dg
|
||||
};
|
||||
return new Body(params);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Body;
|
201
plugins/layout.forceAtlas2/force.worker.js
Normal file
201
plugins/layout.forceAtlas2/force.worker.js
Normal file
@ -0,0 +1,201 @@
|
||||
// console.log('aa');
|
||||
// onmessage = function(event) {
|
||||
// const {
|
||||
// nodes,
|
||||
// edges,
|
||||
// kr,
|
||||
// kg,
|
||||
// mode,
|
||||
// prev_overlapping,
|
||||
// dissuade_hubs,
|
||||
// barnes_hut,
|
||||
// ks,
|
||||
// ksmax,
|
||||
// tao,
|
||||
// center,
|
||||
// widths
|
||||
// } = event.data.params;
|
||||
// let {
|
||||
// pre_Forces,
|
||||
// Forces,
|
||||
// iter,
|
||||
// prevo_iter,
|
||||
// kr_prime,
|
||||
// start,
|
||||
// end,
|
||||
// estart,
|
||||
// eend
|
||||
// } = event.data;
|
||||
|
||||
// const size = nodes.length;
|
||||
// const esize = edges.length;
|
||||
|
||||
// for (let i = start; i < end; i += 1) {
|
||||
// pre_Forces[2 * i] = Forces[2 * i];
|
||||
// pre_Forces[2 * i + 1] = Forces[2 * i + 1];
|
||||
// Forces[2 * i] = 0;
|
||||
// Forces[2 * i + 1] = 0;
|
||||
// }
|
||||
// // // attractive forces, existing on every actual edge
|
||||
// Forces = getAttrForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, widths, estart, eend);
|
||||
// // // // repulsive forces and Gravity, existing on every node pair
|
||||
// // // // if prev_overlapping, using the no-optimized method in the last prevo_iter instead.
|
||||
// // if (barnes_hut && ((prev_overlapping && iter > prevo_iter) || !prev_overlapping)) {
|
||||
// // Forces = getOptRepGraForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, center, bodies);
|
||||
// // } else {
|
||||
// Forces = getRepGraForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, center, widths, start, end);
|
||||
// // }
|
||||
// // // update the positions
|
||||
// // const res = updatePos(size, nodes, Forces, pre_Forces, SG, ks, ksmax, tao);
|
||||
// // nodes = res[0];
|
||||
// // SG = res[1];
|
||||
// // iter -= 1;
|
||||
// };
|
||||
|
||||
|
||||
// function getAttrForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, widths, estart, eend) {
|
||||
// for (let i = estart; i < eend; i += 1) {
|
||||
// // const source_node = graph.find(edges[i].source).getModel();
|
||||
// // const target_node = graph.find(edges[i].target).getModel();
|
||||
// let source_node;
|
||||
// let target_node;
|
||||
// let source_idx;
|
||||
// let target_idx;
|
||||
// for (let j = 0; j < size; j += 1) {
|
||||
// if (nodes[j].id === edges[i].source) {
|
||||
// source_node = nodes[j];
|
||||
// source_idx = j;
|
||||
// } else if (nodes[j].id === edges[i].target) {
|
||||
// target_node = nodes[j];
|
||||
// target_idx = j;
|
||||
// }
|
||||
// }
|
||||
// let dir = [ target_node.x - source_node.x, target_node.y - source_node.y ];
|
||||
// let eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
// eucli_dis = eucli_dis < 0.0001 ? 0.0001 : eucli_dis;
|
||||
// dir[0] = dir[0] / eucli_dis;
|
||||
// dir[1] = dir[1] / eucli_dis;
|
||||
// // the force
|
||||
// if (prev_overlapping && iter < prevo_iter) eucli_dis = eucli_dis - widths[source_idx] - widths[target_idx];
|
||||
// let Fa1 = eucli_dis;
|
||||
// let Fa2 = Fa1;
|
||||
// if (mode === 'linlog') {
|
||||
// Fa1 = Math.log(1 + eucli_dis);
|
||||
// Fa2 = Fa1;
|
||||
// }
|
||||
// if (dissuade_hubs) {
|
||||
// Fa1 = eucli_dis / source_node.degree;
|
||||
// Fa2 = eucli_dis / target_node.degree;
|
||||
// }
|
||||
// if (prev_overlapping && iter < prevo_iter && eucli_dis <= 0) {
|
||||
// Fa1 = 0;
|
||||
// Fa2 = 0;
|
||||
// } else if (prev_overlapping && iter < prevo_iter && eucli_dis > 0) {
|
||||
// Fa1 = eucli_dis;
|
||||
// Fa2 = eucli_dis;
|
||||
// }
|
||||
// Forces[2 * source_node.index] += Fa1 * dir[0];
|
||||
// Forces[2 * target_node.index] -= Fa2 * dir[0];
|
||||
// Forces[2 * source_node.index + 1] += Fa1 * dir[1];
|
||||
// Forces[2 * target_node.index + 1] -= Fa2 * dir[1];
|
||||
// dir = null;
|
||||
// }
|
||||
// return Forces;
|
||||
// }
|
||||
|
||||
// function getRepGraForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, center, widths, start, end) {
|
||||
// for (let i = start; i < end; i += 1) {
|
||||
// for (let j = i + 1; j < size; j += 1) {
|
||||
// let dir = [nodes[j].x - nodes[i].x, nodes[j].y - nodes[i].y];
|
||||
// let eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
// eucli_dis = eucli_dis < 0.0001 ? 0.0001 : eucli_dis;
|
||||
// dir[0] = dir[0] / eucli_dis;
|
||||
// dir[1] = dir[1] / eucli_dis;
|
||||
|
||||
// if (prev_overlapping && iter < prevo_iter) eucli_dis = eucli_dis - widths[i] - widths[j];
|
||||
|
||||
// let Fr = kr * (nodes[i].degree + 1) * (nodes[j].degree + 1) / eucli_dis;
|
||||
|
||||
// if (prev_overlapping && iter < prevo_iter && eucli_dis < 0) {
|
||||
// Fr = kr_prime * (nodes[i].degree + 1) * (nodes[j].degree + 1);
|
||||
// } else if (prev_overlapping && iter < prevo_iter && eucli_dis === 0) {
|
||||
// Fr = 0;
|
||||
// } else if (prev_overlapping && iter < prevo_iter && eucli_dis > 0) {
|
||||
// Fr = kr * (nodes[i].degree + 1) * (nodes[j].degree + 1) / eucli_dis;
|
||||
// }
|
||||
// Forces[2 * i] -= Fr * dir[0];
|
||||
// Forces[2 * j] += Fr * dir[0];
|
||||
// Forces[2 * i + 1] -= Fr * dir[1];
|
||||
// Forces[2 * j + 1] += Fr * dir[1];
|
||||
// dir = null;
|
||||
// }
|
||||
|
||||
// // gravity
|
||||
// let dir = [nodes[i].x - center.x, nodes[i].y - center.y];
|
||||
// const eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
// dir[0] = dir[0] / eucli_dis;
|
||||
// dir[1] = dir[1] / eucli_dis;
|
||||
// const Fg = kg * (nodes[i].degree + 1);
|
||||
// Forces[2 * i] -= Fg * dir[0];
|
||||
// Forces[2 * i + 1] -= Fg * dir[1];
|
||||
// dir = null;
|
||||
// }
|
||||
// return Forces;
|
||||
// }
|
||||
|
||||
// // function getOptRepGraForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, ct, bodies) {
|
||||
// // let minx = 9e10,
|
||||
// // maxx = -9e10,
|
||||
// // miny = 9e10,
|
||||
// // maxy = -9e10;
|
||||
// // for (let i = 0; i < size; i += 1) {
|
||||
// // bodies[i].setPos(nodes[i].x, nodes[i].y);
|
||||
// // if (nodes[i].x >= maxx) maxx = nodes[i].x;
|
||||
// // if (nodes[i].x <= minx) minx = nodes[i].x;
|
||||
// // if (nodes[i].y >= maxy) maxy = nodes[i].y;
|
||||
// // if (nodes[i].y <= miny) miny = nodes[i].y;
|
||||
// // }
|
||||
|
||||
// // let width = Math.max(maxx - minx, maxy - miny);
|
||||
|
||||
// // let quad_params = {
|
||||
// // xmid: (maxx + minx) / 2,
|
||||
// // ymid: (maxy + miny) / 2,
|
||||
// // length: width,
|
||||
// // mass_center: ct,
|
||||
// // mass: size
|
||||
// // };
|
||||
// // let quad = new Quad(quad_params);
|
||||
// // let quad_tree = new QuadTree(quad);
|
||||
|
||||
// // // build the tree, insert the nodes(quads) into the tree
|
||||
// // for (let i = 0; i < size; i += 1) {
|
||||
// // if (bodies[i].in(quad)) quad_tree.insert(bodies[i]);
|
||||
// // }
|
||||
// // // update the repulsive forces and the gravity.
|
||||
// // for (let i = 0; i < size; i += 1) {
|
||||
// // bodies[i].resetForce();
|
||||
// // quad_tree.updateForce(bodies[i]);
|
||||
// // Forces[2 * i] -= bodies[i].fx;
|
||||
// // Forces[2 * i + 1] -= bodies[i].fy;
|
||||
|
||||
// // // gravity
|
||||
// // let dir = [nodes[i].x - ct.x, nodes[i].y - ct.y];
|
||||
// // let eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
// // eucli_dis = eucli_dis < 0.0001 ? 0.0001 : eucli_dis;
|
||||
// // dir[0] = dir[0] / eucli_dis;
|
||||
// // dir[1] = dir[1] / eucli_dis;
|
||||
// // let Fg = kg * (nodes[i].degree + 1);
|
||||
// // Forces[2 * i] -= Fg * dir[0];
|
||||
// // Forces[2 * i + 1] -= Fg * dir[1];
|
||||
|
||||
// // eucli_dis = null;
|
||||
// // Fg = null;
|
||||
// // dir = null;
|
||||
// // }
|
||||
// // quad_params = null;
|
||||
// // quad = null;
|
||||
// // quad_tree = null;
|
||||
// // width = null;
|
||||
// // return Forces;
|
||||
// // }
|
@ -4,10 +4,7 @@
|
||||
*/
|
||||
const G6 = require('@antv/g6');
|
||||
const Util = G6.Util;
|
||||
const Body = require('./quadTree/body');
|
||||
const Quad = require('./quadTree/quad');
|
||||
const QuadTree = require('./quadTree/quadTree');
|
||||
// const Worker = require('worker-loader?inline!./worker');
|
||||
const Worker = require('worker-loader?name=[name].js!./layout.worker');
|
||||
|
||||
// import StaticsWorker from 'worker-loader?inline!./statistics.worker.js';
|
||||
class Layout {
|
||||
@ -127,295 +124,41 @@ class Layout {
|
||||
x: width / 2,
|
||||
y: height / 2
|
||||
};
|
||||
|
||||
// const worker = new Worker({ type: 'module' });// { type: 'module' }
|
||||
// the whidth of each nodes
|
||||
// const widths = [];
|
||||
// const size = nodes.length;
|
||||
// for (let i = 0; i < size; i += 1) {
|
||||
// widths[i] = graph.getNodes()[i].getBBox().maxX - graph.getNodes()[i].getBBox().minX;
|
||||
// }
|
||||
// console.log(worker)
|
||||
// const obj = {
|
||||
// nodes,
|
||||
// edges,
|
||||
// kr,
|
||||
// kg,
|
||||
// mode,
|
||||
// prev_overlapping,
|
||||
// dissuade_hubs,
|
||||
// barnes_hut,
|
||||
// max_iteration,
|
||||
// ks,
|
||||
// ksmax,
|
||||
// tao,
|
||||
// center,
|
||||
// widths
|
||||
// };
|
||||
// obj = JSON.parse(JSON.stringify(obj));
|
||||
// worker.postMessage(obj);
|
||||
// worker.onmessage = function(event) {
|
||||
// console.log(event.data);
|
||||
// };
|
||||
const widths = [];
|
||||
const size = nodes.length;
|
||||
const esize = edges.length;
|
||||
|
||||
let SG = 0;
|
||||
const bodies = [];
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
nodes[i].index = i;
|
||||
nodes[i].degree = 0;
|
||||
nodes[i].x = Math.random() * 1000;
|
||||
nodes[i].y = Math.random() * 1000;
|
||||
widths[i] = graph.getNodes()[i].getBBox().maxX;
|
||||
}
|
||||
for (let i = 0; i < esize; i += 1) {
|
||||
const node1 = graph.find(edges[i].source).getModel();
|
||||
const node2 = graph.find(edges[i].target).getModel();
|
||||
nodes[node1.index].degree += 1;
|
||||
nodes[node2.index].degree += 1;
|
||||
}
|
||||
|
||||
const kr_prime = 100;
|
||||
let iter = max_iteration;
|
||||
const prevo_iter = 50;
|
||||
let Forces = [];
|
||||
const pre_Forces = [];
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
Forces[2 * i] = 0;
|
||||
Forces[2 * i + 1] = 0;
|
||||
|
||||
if (barnes_hut) {
|
||||
let params = {
|
||||
id: i,
|
||||
rx: nodes[i].x,
|
||||
ry: nodes[i].y,
|
||||
mass: 1,
|
||||
G: kr,
|
||||
degree: nodes[i].degree
|
||||
};
|
||||
bodies[i] = new Body(params);
|
||||
params = null;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
pre_Forces[2 * i] = Forces[2 * i];
|
||||
pre_Forces[2 * i + 1] = Forces[2 * i + 1];
|
||||
Forces[2 * i] = 0;
|
||||
Forces[2 * i + 1] = 0;
|
||||
}
|
||||
// attractive forces, existing on every actual edge
|
||||
Forces = this.getAttrForces(graph, nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, widths);
|
||||
|
||||
// repulsive forces and Gravity, existing on every node pair
|
||||
// if prev_overlapping, using the no-optimized method in the last prevo_iter instead.
|
||||
if (barnes_hut && ((prev_overlapping && iter > prevo_iter) || !prev_overlapping)) {
|
||||
Forces = this.getOptRepGraForces(graph, nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, center, bodies);
|
||||
} else {
|
||||
Forces = this.getRepGraForces(graph, nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, center, widths);
|
||||
}
|
||||
|
||||
// update the positions
|
||||
const res = this.updatePos(size, nodes, Forces, pre_Forces, SG, ks, ksmax, tao);
|
||||
nodes = res[0];
|
||||
SG = res[1];
|
||||
iter -= 1;
|
||||
} while (iter > 0);
|
||||
}
|
||||
|
||||
|
||||
getAttrForces(graph, nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, widths) {
|
||||
for (let i = 0; i < esize; i += 1) {
|
||||
const source_node = graph.find(edges[i].source).getModel();
|
||||
const target_node = graph.find(edges[i].target).getModel();
|
||||
// const source_node, target_node;
|
||||
// const source_idx, target_idx;
|
||||
// for (let j = 0; j < size; j += 1) {
|
||||
// if (nodes[j].id === edges[i].source) {
|
||||
// source_node = nodes[j];
|
||||
// source_idx = j;
|
||||
// } else if (nodes[j].id === edges[i].target) {
|
||||
// target_node = nodes[j];
|
||||
// target_idx = j;
|
||||
// }
|
||||
// }
|
||||
let dir = [target_node.x - source_node.x, target_node.y - source_node.y];
|
||||
let eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
eucli_dis = eucli_dis < 0.0001 ? 0.0001 : eucli_dis;
|
||||
dir[0] = dir[0] / eucli_dis;
|
||||
dir[1] = dir[1] / eucli_dis;
|
||||
// the force
|
||||
// if (prev_overlapping && iter < prevo_iter) eucli_dis = eucli_dis - widths[source_idx] - widths[target_idx] ;
|
||||
if (prev_overlapping && iter < prevo_iter) eucli_dis = eucli_dis - graph.find(source_node.id).getBBox().maxX - graph.find(target_node.id).getBBox().maxX;
|
||||
let Fa1 = eucli_dis;
|
||||
let Fa2 = Fa1;
|
||||
if (mode === 'linlog') {
|
||||
Fa1 = Math.log(1 + eucli_dis);
|
||||
Fa2 = Fa1;
|
||||
}
|
||||
if (dissuade_hubs) {
|
||||
Fa1 = eucli_dis / source_node.degree;
|
||||
Fa2 = eucli_dis / target_node.degree;
|
||||
}
|
||||
if (prev_overlapping && iter < prevo_iter && eucli_dis <= 0) {
|
||||
Fa1 = 0;
|
||||
Fa2 = 0;
|
||||
} else if (prev_overlapping && iter < prevo_iter && eucli_dis > 0) {
|
||||
Fa1 = eucli_dis;
|
||||
Fa2 = eucli_dis;
|
||||
}
|
||||
Forces[2 * source_node.index] += Fa1 * dir[0];
|
||||
Forces[2 * target_node.index] -= Fa2 * dir[0];
|
||||
Forces[2 * source_node.index + 1] += Fa1 * dir[1];
|
||||
Forces[2 * target_node.index + 1] -= Fa2 * dir[1];
|
||||
dir = null;
|
||||
}
|
||||
return Forces;
|
||||
}
|
||||
|
||||
getRepGraForces(graph, nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, center, widths) {
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
for (let j = i + 1; j < size; j += 1) {
|
||||
let dir = [nodes[j].x - nodes[i].x, nodes[j].y - nodes[i].y];
|
||||
let eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
eucli_dis = eucli_dis < 0.0001 ? 0.0001 : eucli_dis;
|
||||
dir[0] = dir[0] / eucli_dis;
|
||||
dir[1] = dir[1] / eucli_dis;
|
||||
|
||||
if (prev_overlapping && iter < prevo_iter) eucli_dis = eucli_dis - whidths[i] - widths[j];
|
||||
|
||||
let Fr = kr * (nodes[i].degree + 1) * (nodes[j].degree + 1) / eucli_dis;
|
||||
|
||||
if (prev_overlapping && iter < prevo_iter && eucli_dis < 0) {
|
||||
Fr = kr_prime * (nodes[i].degree + 1) * (nodes[j].degree + 1);
|
||||
} else if (prev_overlapping && iter < prevo_iter && eucli_dis === 0) {
|
||||
Fr = 0;
|
||||
} else if (prev_overlapping && iter < prevo_iter && eucli_dis > 0) {
|
||||
Fr = kr * (nodes[i].degree + 1) * (nodes[j].degree + 1) / eucli_dis;
|
||||
}
|
||||
Forces[2 * i] -= Fr * dir[0];
|
||||
Forces[2 * j] += Fr * dir[0];
|
||||
Forces[2 * i + 1] -= Fr * dir[1];
|
||||
Forces[2 * j + 1] += Fr * dir[1];
|
||||
dir = null;
|
||||
}
|
||||
|
||||
// gravity
|
||||
let dir = [nodes[i].x - center.x, nodes[i].y - center.y];
|
||||
const eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
dir[0] = dir[0] / eucli_dis;
|
||||
dir[1] = dir[1] / eucli_dis;
|
||||
const Fg = kg * (nodes[i].degree + 1);
|
||||
Forces[2 * i] -= Fg * dir[0];
|
||||
Forces[2 * i + 1] -= Fg * dir[1];
|
||||
dir = null;
|
||||
}
|
||||
return Forces;
|
||||
}
|
||||
getOptRepGraForces(graph, nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, ct, bodies) {
|
||||
let minx = 9e10,
|
||||
maxx = -9e10,
|
||||
miny = 9e10,
|
||||
maxy = -9e10;
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
bodies[i].setPos(nodes[i].x, nodes[i].y);
|
||||
if (nodes[i].x >= maxx) maxx = nodes[i].x;
|
||||
if (nodes[i].x <= minx) minx = nodes[i].x;
|
||||
if (nodes[i].y >= maxy) maxy = nodes[i].y;
|
||||
if (nodes[i].y <= miny) miny = nodes[i].y;
|
||||
}
|
||||
|
||||
let width = Math.max(maxx - minx, maxy - miny);
|
||||
|
||||
let quad_params = {
|
||||
xmid: (maxx + minx) / 2,
|
||||
ymid: (maxy + miny) / 2,
|
||||
length: width,
|
||||
mass_center: ct,
|
||||
mass: size
|
||||
const obj = {
|
||||
nodes,
|
||||
edges,
|
||||
kr,
|
||||
kg,
|
||||
mode,
|
||||
prev_overlapping,
|
||||
dissuade_hubs,
|
||||
barnes_hut,
|
||||
max_iteration,
|
||||
ks,
|
||||
ksmax,
|
||||
tao,
|
||||
center,
|
||||
widths
|
||||
};
|
||||
let quad = new Quad(quad_params);
|
||||
let quad_tree = new QuadTree(quad);
|
||||
|
||||
// build the tree, insert the nodes(quads) into the tree
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
if (bodies[i].in(quad)) quad_tree.insert(bodies[i]);
|
||||
}
|
||||
// update the repulsive forces and the gravity.
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
bodies[i].resetForce();
|
||||
quad_tree.updateForce(bodies[i]);
|
||||
Forces[2 * i] -= bodies[i].fx;
|
||||
Forces[2 * i + 1] -= bodies[i].fy;
|
||||
|
||||
// gravity
|
||||
let dir = [nodes[i].x - ct.x, nodes[i].y - ct.y];
|
||||
let eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
eucli_dis = eucli_dis < 0.0001 ? 0.0001 : eucli_dis;
|
||||
dir[0] = dir[0] / eucli_dis;
|
||||
dir[1] = dir[1] / eucli_dis;
|
||||
let Fg = kg * (nodes[i].degree + 1);
|
||||
Forces[2 * i] -= Fg * dir[0];
|
||||
Forces[2 * i + 1] -= Fg * dir[1];
|
||||
|
||||
eucli_dis = null;
|
||||
Fg = null;
|
||||
dir = null;
|
||||
}
|
||||
quad_params = null;
|
||||
quad = null;
|
||||
quad_tree = null;
|
||||
width = null;
|
||||
return Forces;
|
||||
const worker = new Worker();// { type: 'module' }
|
||||
worker.postMessage(obj);
|
||||
worker.onmessage = function(event) {
|
||||
this.nodes = event.data;
|
||||
const graph_nodes = graph.getNodes();
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
const model = graph_nodes[i].getModel();
|
||||
model.x = this.nodes[i].x;
|
||||
model.y = this.nodes[i].y;
|
||||
}
|
||||
graph.changeLayout();
|
||||
};
|
||||
}
|
||||
|
||||
updatePos(size, nodes, Forces, pre_Forces, SG, ks, ksmax, tao) {
|
||||
let swgns = [];
|
||||
let trans = [];
|
||||
// swg(G) and tra(G)
|
||||
let swgG = 0;
|
||||
let traG = 0;
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
const minus = [Forces[2 * i] - pre_Forces[2 * i],
|
||||
Forces[2 * i + 1] - pre_Forces[2 * i + 1]
|
||||
];
|
||||
const minus_norm = Math.hypot(minus[0], minus[1]);
|
||||
const add = [Forces[2 * i] + pre_Forces[2 * i],
|
||||
Forces[2 * i + 1] + pre_Forces[2 * i + 1]
|
||||
];
|
||||
const add_norm = Math.hypot(add[0], add[1]);
|
||||
|
||||
swgns[i] = minus_norm;
|
||||
trans[i] = add_norm / 2;
|
||||
|
||||
swgG += (nodes[i].degree + 1) * swgns[i];
|
||||
traG += (nodes[i].degree + 1) * trans[i];
|
||||
}
|
||||
|
||||
let pre_SG = SG;
|
||||
SG = tao * traG / swgG;
|
||||
if (pre_SG !== 0) {
|
||||
SG = SG > (1.5 * pre_SG) ? (1.5 * pre_SG) : SG;
|
||||
}
|
||||
// update the node positions
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
let Sn = ks * SG / (1 + SG * Math.sqrt(swgns[i]));
|
||||
let absForce = Math.hypot(Forces[2 * i], Forces[2 * i + 1]);
|
||||
absForce = absForce < 0.0001 ? 0.0001 : absForce;
|
||||
const max = ksmax / absForce;
|
||||
Sn = Sn > max ? max : Sn;
|
||||
const Dn_x = Sn * Forces[2 * i];
|
||||
const Dn_y = Sn * Forces[2 * i + 1];
|
||||
nodes[i].x += Dn_x;
|
||||
nodes[i].y += Dn_y;
|
||||
}
|
||||
swgns = null;
|
||||
trans = null;
|
||||
pre_SG = null;
|
||||
return [nodes, SG];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Layout;
|
||||
|
392
plugins/layout.forceAtlas2/layout.worker.js
Normal file
392
plugins/layout.forceAtlas2/layout.worker.js
Normal file
@ -0,0 +1,392 @@
|
||||
const Body = require('./body');
|
||||
const Quad = require('./quad');
|
||||
const QuadTree = require('./quadTree');
|
||||
const ForceWorker = require('./force.worker');
|
||||
// const ForceWorker = require('./force.worker');
|
||||
// console.log('ass absdd')
|
||||
const force_worker = new ForceWorker();
|
||||
onmessage = function(event) {
|
||||
let {
|
||||
nodes,
|
||||
edges,
|
||||
kr,
|
||||
kg,
|
||||
mode,
|
||||
prev_overlapping,
|
||||
dissuade_hubs,
|
||||
barnes_hut,
|
||||
max_iteration,
|
||||
ks,
|
||||
ksmax,
|
||||
tao,
|
||||
center,
|
||||
widths
|
||||
} = event.data;
|
||||
|
||||
const size = nodes.length;
|
||||
const esize = edges.length;
|
||||
|
||||
let SG = 0;
|
||||
const bodies = [];
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
nodes[i].index = i;
|
||||
nodes[i].degree = 0;
|
||||
nodes[i].x = Math.random() * 1000;
|
||||
nodes[i].y = Math.random() * 1000;
|
||||
}
|
||||
for (let i = 0; i < esize; i += 1) {
|
||||
let node1;
|
||||
let node2;
|
||||
for (let j = 0; j < size; j += 1) {
|
||||
if (nodes[j].id === edges[i].source) {
|
||||
node1 = nodes[j];
|
||||
} else if (nodes[j].id === edges[i].target) {
|
||||
node2 = nodes[j];
|
||||
}
|
||||
}
|
||||
// // const node1 = graph.find(edges[i].source).getModel();
|
||||
// // const node2 = graph.find(edges[i].target).getModel();
|
||||
nodes[node1.index].degree += 1;
|
||||
nodes[node2.index].degree += 1;
|
||||
}
|
||||
|
||||
const kr_prime = 100;
|
||||
let iter = max_iteration;
|
||||
const prevo_iter = 50;
|
||||
let Forces = [];
|
||||
const pre_Forces = [];
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
Forces[2 * i] = 0;
|
||||
Forces[2 * i + 1] = 0;
|
||||
|
||||
if (barnes_hut) {
|
||||
let params = {
|
||||
id: i,
|
||||
rx: nodes[i].x,
|
||||
ry: nodes[i].y,
|
||||
mass: 1,
|
||||
G: kr,
|
||||
degree: nodes[i].degree
|
||||
};
|
||||
bodies[i] = new Body(params);
|
||||
params = null;
|
||||
}
|
||||
}
|
||||
|
||||
let worker_back = 0;
|
||||
let workerList = [];
|
||||
const worker_num = 10;
|
||||
const worker_capacity = Math.ceil(size / worker_num);
|
||||
const worker_edge_capacity = Math.ceil(esize / worker_num);
|
||||
|
||||
do {
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
pre_Forces[2 * i] = Forces[2 * i];
|
||||
pre_Forces[2 * i + 1] = Forces[2 * i + 1];
|
||||
Forces[2 * i] = 0;
|
||||
Forces[2 * i + 1] = 0;
|
||||
}
|
||||
|
||||
if (!barnes_hut) {
|
||||
workerList = [];
|
||||
for (let i = 0; i < worker_num; i += 1) {
|
||||
// console.log(i);
|
||||
// const force_worker = new ForceWorker();
|
||||
// workerList.push(new ForceWorker());
|
||||
|
||||
// const start_idx = i * worker_capacity;
|
||||
// let end_idx = start_idx + worker_capacity - 1;
|
||||
// end_idx = end_idx > size ? size : end_idx;
|
||||
// const estart_idx = i * worker_edge_capacity;
|
||||
// let eend_idx = estart_idx + worker_edge_capacity - 1;
|
||||
// eend_idx = eend_idx > esize ? esize : eend_idx;
|
||||
|
||||
// force_worker.postMessage({
|
||||
// params: event.data,
|
||||
// pre_Forces,
|
||||
// Forces,
|
||||
// iter,
|
||||
// prevo_iter,
|
||||
// kr_prime,
|
||||
// index: i,
|
||||
// start: start_idx,
|
||||
// end: end_idx,
|
||||
// estart: estart_idx,
|
||||
// eend: eend_idx
|
||||
// });
|
||||
// force_worker.onMessage = function(event) {
|
||||
// worker_back += 1;
|
||||
// const start = event.data.start;
|
||||
// const end = event.data.end;
|
||||
// const worker_Forces = event.data.Forces;
|
||||
// for (let i = start; i < end; i += 1) {
|
||||
// Forces[2 * i] = worker_Forces[i].x;
|
||||
// Forces[2 * i + 1].y = worker_Forces[i].y;
|
||||
// }
|
||||
// if (worker_back >= worker_num) {
|
||||
// // // update the positions
|
||||
// const res = updatePos(size, nodes, Forces, pre_Forces, SG, ks, ksmax, tao);
|
||||
// nodes = res[0];
|
||||
// SG = res[1];
|
||||
// iter -= 1;
|
||||
// return;
|
||||
// }
|
||||
// };
|
||||
}
|
||||
// workerList.map(function(worker, idx) {
|
||||
// worker.addEventListener('message', function(e) {
|
||||
// workerList.map(function(_worker) {
|
||||
// _worker.terminate();
|
||||
// });
|
||||
// });
|
||||
// const start_idx = idx * worker_capacity;
|
||||
// let end_idx = start_idx + worker_capacity - 1;
|
||||
// end_idx = end_idx > size ? size : end_idx;
|
||||
// const estart_idx = idx * worker_edge_capacity;
|
||||
// let eend_idx = estart_idx + worker_edge_capacity - 1;
|
||||
// eend_idx = eend_idx > esize ? esize : eend_idx;
|
||||
|
||||
// worker.postMessage({
|
||||
// params: event.data,
|
||||
// pre_Forces,
|
||||
// Forces,
|
||||
// iter,
|
||||
// prevo_iter,
|
||||
// kr_prime,
|
||||
// index: idx,
|
||||
// start: start_idx,
|
||||
// end: end_idx,
|
||||
// estart: estart_idx,
|
||||
// eend: eend_idx
|
||||
// });
|
||||
// worker.onMessage = function(event) {
|
||||
// worker_back += 1;
|
||||
// const start = event.data.start;
|
||||
// const end = event.data.end;
|
||||
// const worker_Forces = event.data.Forces;
|
||||
// for (let i = start; i < end; i += 1) {
|
||||
// Forces[2 * i] = worker_Forces[i].x;
|
||||
// Forces[2 * i + 1].y = worker_Forces[i].y;
|
||||
// }
|
||||
// if (worker_back >= worker_num) {
|
||||
// // // update the positions
|
||||
// const res = updatePos(size, nodes, Forces, pre_Forces, SG, ks, ksmax, tao);
|
||||
// nodes = res[0];
|
||||
// SG = res[1];
|
||||
// iter -= 1;
|
||||
// return;
|
||||
// }
|
||||
// };
|
||||
// });
|
||||
} else {
|
||||
// // attractive forces, existing on every actual edge
|
||||
Forces = getAttrForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, widths);
|
||||
// // // repulsive forces and Gravity, existing on every node pair
|
||||
// // // if prev_overlapping, using the no-optimized method in the last prevo_iter instead.
|
||||
if (barnes_hut && ((prev_overlapping && iter > prevo_iter) || !prev_overlapping)) {
|
||||
Forces = getOptRepGraForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, center, bodies);
|
||||
} else {
|
||||
Forces = getRepGraForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, center, widths);
|
||||
}
|
||||
// // update the positions
|
||||
const res = updatePos(size, nodes, Forces, pre_Forces, SG, ks, ksmax, tao);
|
||||
nodes = res[0];
|
||||
SG = res[1];
|
||||
iter -= 1;
|
||||
}
|
||||
} while (iter > 0);
|
||||
self.postMessage(nodes);
|
||||
};
|
||||
|
||||
function getAttrForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, widths) {
|
||||
for (let i = 0; i < esize; i += 1) {
|
||||
// const source_node = graph.find(edges[i].source).getModel();
|
||||
// const target_node = graph.find(edges[i].target).getModel();
|
||||
let source_node;
|
||||
let target_node;
|
||||
let source_idx;
|
||||
let target_idx;
|
||||
for (let j = 0; j < size; j += 1) {
|
||||
if (nodes[j].id === edges[i].source) {
|
||||
source_node = nodes[j];
|
||||
source_idx = j;
|
||||
} else if (nodes[j].id === edges[i].target) {
|
||||
target_node = nodes[j];
|
||||
target_idx = j;
|
||||
}
|
||||
}
|
||||
let dir = [target_node.x - source_node.x, target_node.y - source_node.y];
|
||||
let eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
eucli_dis = eucli_dis < 0.0001 ? 0.0001 : eucli_dis;
|
||||
dir[0] = dir[0] / eucli_dis;
|
||||
dir[1] = dir[1] / eucli_dis;
|
||||
// the force
|
||||
if (prev_overlapping && iter < prevo_iter) eucli_dis = eucli_dis - widths[source_idx] - widths[target_idx];
|
||||
let Fa1 = eucli_dis;
|
||||
let Fa2 = Fa1;
|
||||
if (mode === 'linlog') {
|
||||
Fa1 = Math.log(1 + eucli_dis);
|
||||
Fa2 = Fa1;
|
||||
}
|
||||
if (dissuade_hubs) {
|
||||
Fa1 = eucli_dis / source_node.degree;
|
||||
Fa2 = eucli_dis / target_node.degree;
|
||||
}
|
||||
if (prev_overlapping && iter < prevo_iter && eucli_dis <= 0) {
|
||||
Fa1 = 0;
|
||||
Fa2 = 0;
|
||||
} else if (prev_overlapping && iter < prevo_iter && eucli_dis > 0) {
|
||||
Fa1 = eucli_dis;
|
||||
Fa2 = eucli_dis;
|
||||
}
|
||||
Forces[2 * source_node.index] += Fa1 * dir[0];
|
||||
Forces[2 * target_node.index] -= Fa2 * dir[0];
|
||||
Forces[2 * source_node.index + 1] += Fa1 * dir[1];
|
||||
Forces[2 * target_node.index + 1] -= Fa2 * dir[1];
|
||||
dir = null;
|
||||
}
|
||||
return Forces;
|
||||
}
|
||||
|
||||
function getRepGraForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, center, widths) {
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
for (let j = i + 1; j < size; j += 1) {
|
||||
let dir = [nodes[j].x - nodes[i].x, nodes[j].y - nodes[i].y];
|
||||
let eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
eucli_dis = eucli_dis < 0.0001 ? 0.0001 : eucli_dis;
|
||||
dir[0] = dir[0] / eucli_dis;
|
||||
dir[1] = dir[1] / eucli_dis;
|
||||
|
||||
if (prev_overlapping && iter < prevo_iter) eucli_dis = eucli_dis - widths[i] - widths[j];
|
||||
|
||||
let Fr = kr * (nodes[i].degree + 1) * (nodes[j].degree + 1) / eucli_dis;
|
||||
|
||||
if (prev_overlapping && iter < prevo_iter && eucli_dis < 0) {
|
||||
Fr = kr_prime * (nodes[i].degree + 1) * (nodes[j].degree + 1);
|
||||
} else if (prev_overlapping && iter < prevo_iter && eucli_dis === 0) {
|
||||
Fr = 0;
|
||||
} else if (prev_overlapping && iter < prevo_iter && eucli_dis > 0) {
|
||||
Fr = kr * (nodes[i].degree + 1) * (nodes[j].degree + 1) / eucli_dis;
|
||||
}
|
||||
Forces[2 * i] -= Fr * dir[0];
|
||||
Forces[2 * j] += Fr * dir[0];
|
||||
Forces[2 * i + 1] -= Fr * dir[1];
|
||||
Forces[2 * j + 1] += Fr * dir[1];
|
||||
dir = null;
|
||||
}
|
||||
|
||||
// gravity
|
||||
let dir = [nodes[i].x - center.x, nodes[i].y - center.y];
|
||||
const eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
dir[0] = dir[0] / eucli_dis;
|
||||
dir[1] = dir[1] / eucli_dis;
|
||||
const Fg = kg * (nodes[i].degree + 1);
|
||||
Forces[2 * i] -= Fg * dir[0];
|
||||
Forces[2 * i + 1] -= Fg * dir[1];
|
||||
dir = null;
|
||||
}
|
||||
return Forces;
|
||||
}
|
||||
|
||||
function getOptRepGraForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, ct, bodies) {
|
||||
let minx = 9e10,
|
||||
maxx = -9e10,
|
||||
miny = 9e10,
|
||||
maxy = -9e10;
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
bodies[i].setPos(nodes[i].x, nodes[i].y);
|
||||
if (nodes[i].x >= maxx) maxx = nodes[i].x;
|
||||
if (nodes[i].x <= minx) minx = nodes[i].x;
|
||||
if (nodes[i].y >= maxy) maxy = nodes[i].y;
|
||||
if (nodes[i].y <= miny) miny = nodes[i].y;
|
||||
}
|
||||
|
||||
let width = Math.max(maxx - minx, maxy - miny);
|
||||
|
||||
let quad_params = {
|
||||
xmid: (maxx + minx) / 2,
|
||||
ymid: (maxy + miny) / 2,
|
||||
length: width,
|
||||
mass_center: ct,
|
||||
mass: size
|
||||
};
|
||||
let quad = new Quad(quad_params);
|
||||
let quad_tree = new QuadTree(quad);
|
||||
|
||||
// build the tree, insert the nodes(quads) into the tree
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
if (bodies[i].in(quad)) quad_tree.insert(bodies[i]);
|
||||
}
|
||||
// update the repulsive forces and the gravity.
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
bodies[i].resetForce();
|
||||
quad_tree.updateForce(bodies[i]);
|
||||
Forces[2 * i] -= bodies[i].fx;
|
||||
Forces[2 * i + 1] -= bodies[i].fy;
|
||||
|
||||
// gravity
|
||||
let dir = [nodes[i].x - ct.x, nodes[i].y - ct.y];
|
||||
let eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
eucli_dis = eucli_dis < 0.0001 ? 0.0001 : eucli_dis;
|
||||
dir[0] = dir[0] / eucli_dis;
|
||||
dir[1] = dir[1] / eucli_dis;
|
||||
let Fg = kg * (nodes[i].degree + 1);
|
||||
Forces[2 * i] -= Fg * dir[0];
|
||||
Forces[2 * i + 1] -= Fg * dir[1];
|
||||
|
||||
eucli_dis = null;
|
||||
Fg = null;
|
||||
dir = null;
|
||||
}
|
||||
quad_params = null;
|
||||
quad = null;
|
||||
quad_tree = null;
|
||||
width = null;
|
||||
return Forces;
|
||||
}
|
||||
|
||||
function updatePos(size, nodes, Forces, pre_Forces, SG, ks, ksmax, tao) {
|
||||
let swgns = [];
|
||||
let trans = [];
|
||||
// swg(G) and tra(G)
|
||||
let swgG = 0;
|
||||
let traG = 0;
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
const minus = [Forces[2 * i] - pre_Forces[2 * i],
|
||||
Forces[2 * i + 1] - pre_Forces[2 * i + 1]
|
||||
];
|
||||
const minus_norm = Math.hypot(minus[0], minus[1]);
|
||||
const add = [Forces[2 * i] + pre_Forces[2 * i],
|
||||
Forces[2 * i + 1] + pre_Forces[2 * i + 1]
|
||||
];
|
||||
const add_norm = Math.hypot(add[0], add[1]);
|
||||
|
||||
swgns[i] = minus_norm;
|
||||
trans[i] = add_norm / 2;
|
||||
|
||||
swgG += (nodes[i].degree + 1) * swgns[i];
|
||||
traG += (nodes[i].degree + 1) * trans[i];
|
||||
}
|
||||
|
||||
let pre_SG = SG;
|
||||
SG = tao * traG / swgG;
|
||||
if (pre_SG !== 0) {
|
||||
SG = SG > (1.5 * pre_SG) ? (1.5 * pre_SG) : SG;
|
||||
}
|
||||
// update the node positions
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
let Sn = ks * SG / (1 + SG * Math.sqrt(swgns[i]));
|
||||
let absForce = Math.hypot(Forces[2 * i], Forces[2 * i + 1]);
|
||||
absForce = absForce < 0.0001 ? 0.0001 : absForce;
|
||||
const max = ksmax / absForce;
|
||||
Sn = Sn > max ? max : Sn;
|
||||
const Dn_x = Sn * Forces[2 * i];
|
||||
const Dn_y = Sn * Forces[2 * i + 1];
|
||||
nodes[i].x += Dn_x;
|
||||
nodes[i].y += Dn_y;
|
||||
}
|
||||
swgns = null;
|
||||
trans = null;
|
||||
pre_SG = null;
|
||||
return [nodes, SG];
|
||||
}
|
97
plugins/layout.forceAtlas2/quad.js
Normal file
97
plugins/layout.forceAtlas2/quad.js
Normal file
@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @fileOverview quad
|
||||
* @author shiwu.wyy@antfin.com
|
||||
*/
|
||||
|
||||
class Quad {
|
||||
constructor(params) {
|
||||
/**
|
||||
* the center position of this quad
|
||||
* @type {number}
|
||||
*/
|
||||
this.xmid = params.xmid;
|
||||
/**
|
||||
* the center position of this quad
|
||||
* @type {number}
|
||||
*/
|
||||
this.ymid = params.ymid;
|
||||
/**
|
||||
* the length of this quad
|
||||
* @type {number}
|
||||
*/
|
||||
this.length = params.length;
|
||||
/**
|
||||
* the mass center of this quad
|
||||
* @type {number}
|
||||
*/
|
||||
this.mass_center = params.mass_center;
|
||||
/**
|
||||
* the mass of this quad
|
||||
* @type {number}
|
||||
*/
|
||||
this.mass = params.mass;
|
||||
}
|
||||
getLength() {
|
||||
return this.length;
|
||||
}
|
||||
contains(x, y) {
|
||||
const halfLen = this.length / 2;
|
||||
return (x <= this.xmid + halfLen &&
|
||||
x >= this.xmid - halfLen &&
|
||||
y <= this.ymid + halfLen &&
|
||||
y >= this.ymid - halfLen);
|
||||
}
|
||||
// northwest quadrant
|
||||
NW() {
|
||||
const x = this.xmid - this.length / 4;
|
||||
const y = this.ymid + this.length / 4;
|
||||
const len = this.length / 2;
|
||||
const params = {
|
||||
xmid: x,
|
||||
ymid: y,
|
||||
length: len
|
||||
};
|
||||
const NW = new Quad(params);
|
||||
return NW;
|
||||
}
|
||||
// northeast
|
||||
NE() {
|
||||
const x = this.xmid + this.length / 4;
|
||||
const y = this.ymid + this.length / 4;
|
||||
const len = this.length / 2;
|
||||
const params = {
|
||||
xmid: x,
|
||||
ymid: y,
|
||||
length: len
|
||||
};
|
||||
const NE = new Quad(params);
|
||||
return NE;
|
||||
}
|
||||
// southwest
|
||||
SW() {
|
||||
const x = this.xmid - this.length / 4;
|
||||
const y = this.ymid - this.length / 4;
|
||||
const len = this.length / 2;
|
||||
const params = {
|
||||
xmid: x,
|
||||
ymid: y,
|
||||
length: len
|
||||
};
|
||||
const SW = new Quad(params);
|
||||
return SW;
|
||||
}
|
||||
// southeast
|
||||
SE() {
|
||||
const x = this.xmid + this.length / 4;
|
||||
const y = this.ymid - this.length / 4;
|
||||
const len = this.length / 2;
|
||||
const params = {
|
||||
xmid: x,
|
||||
ymid: y,
|
||||
length: len
|
||||
};
|
||||
const SE = new Quad(params);
|
||||
return SE;
|
||||
}
|
||||
}
|
||||
module.exports = Quad;
|
91
plugins/layout.forceAtlas2/quadTree.js
Normal file
91
plugins/layout.forceAtlas2/quadTree.js
Normal file
@ -0,0 +1,91 @@
|
||||
/**
|
||||
* @fileOverview quadTree
|
||||
* @author shiwu.wyy@antfin.com
|
||||
*/
|
||||
class QuadTree {
|
||||
// each quadtree represents a quadrant and an aggregate body
|
||||
// that represents all bodies inside the quadrant
|
||||
constructor(param) {
|
||||
/**
|
||||
* (aggregated) body in this quad
|
||||
* @type {object}
|
||||
*/
|
||||
this.body = null;
|
||||
/**
|
||||
* tree representing the northwest quadrant
|
||||
* @type {object}
|
||||
*/
|
||||
this.quad = null;
|
||||
this.NW = null;
|
||||
this.NE = null;
|
||||
this.SW = null;
|
||||
this.SE = null;
|
||||
/**
|
||||
* threshold
|
||||
* @type {number}
|
||||
*/
|
||||
this.theta = 0.5;
|
||||
if (param != null) this.quad = param;
|
||||
}
|
||||
// insert a body(node) into the tree
|
||||
insert(bo) {
|
||||
// if this node does not contain a body, put the new body bo here
|
||||
if (this.body == null) {
|
||||
this.body = bo;
|
||||
return;
|
||||
}
|
||||
// internal node
|
||||
if (!this._isExternal()) {
|
||||
// update mass info
|
||||
this.body = this.body.add(bo);
|
||||
// insert body into quadrant
|
||||
this._putBody(bo);
|
||||
} else { // external node
|
||||
// divide this region into four children
|
||||
this.NW = new QuadTree(this.quad.NW());
|
||||
this.NE = new QuadTree(this.quad.NE());
|
||||
this.SW = new QuadTree(this.quad.SW());
|
||||
this.SE = new QuadTree(this.quad.SE());
|
||||
|
||||
// insert this body and bo
|
||||
this._putBody(this.body);
|
||||
this._putBody(bo);
|
||||
// update the mass info
|
||||
this.body = this.body.add(bo);
|
||||
|
||||
}
|
||||
}
|
||||
// inserts bo into a quad
|
||||
_putBody(bo) {
|
||||
if (bo.in(this.quad.NW())) this.NW.insert(bo);
|
||||
else if (bo.in(this.quad.NE())) this.NE.insert(bo);
|
||||
else if (bo.in(this.quad.SW())) this.SW.insert(bo);
|
||||
else if (bo.in(this.quad.SE())) this.SE.insert(bo);
|
||||
}
|
||||
_isExternal() {
|
||||
// four children are null
|
||||
return (this.NW == null && this.NE == null && this.SW == null && this.SE == null);
|
||||
}
|
||||
// update the forces
|
||||
updateForce(bo) {
|
||||
if (this.body == null || bo === this.body) {
|
||||
return;
|
||||
}
|
||||
// if the current node is external
|
||||
if (this._isExternal()) bo.addForce(this.body);
|
||||
// internal nodes
|
||||
else {
|
||||
const s = this.quad.getLength();
|
||||
const d = this.body.distanceTo(bo);
|
||||
// b is far enough
|
||||
if ((s / d) < this.theta) bo.addForce(this.body);
|
||||
else {
|
||||
this.NW.updateForce(bo);
|
||||
this.NE.updateForce(bo);
|
||||
this.SW.updateForce(bo);
|
||||
this.SE.updateForce(bo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
module.exports = QuadTree;
|
@ -1,283 +0,0 @@
|
||||
|
||||
// const Body = require('./quadTree/body');
|
||||
// const Quad = require('./quadTree/quad');
|
||||
// const QuadTree = require('./quadTree/quadTree');
|
||||
|
||||
//http://javascript.ruanyifeng.com/htmlapi/webworker.html
|
||||
// importScripts('./quadTree/body.js', './quadTree/quad.js', './quadTree/quadTree.js');
|
||||
|
||||
// import Body from './quadTree/body';
|
||||
|
||||
console.log('bbaaaa');
|
||||
// self.onmessage = function(event) {
|
||||
// let {
|
||||
// nodes,
|
||||
// edges,
|
||||
// kr,
|
||||
// kg,
|
||||
// mode,
|
||||
// prev_overlapping,
|
||||
// dissuade_hubs,
|
||||
// barnes_hut,
|
||||
// max_iteration,
|
||||
// ks,
|
||||
// ksmax,
|
||||
// tao,
|
||||
// center,
|
||||
// widths
|
||||
// } = event.data;
|
||||
// console.log(widths);
|
||||
|
||||
// const size = nodes.length;
|
||||
// const esize = edges.length;
|
||||
|
||||
// let SG = 0;
|
||||
// const bodies = [];
|
||||
// for (let i = 0; i < size; i += 1) {
|
||||
// nodes[i].index = i;
|
||||
// nodes[i].degree = 0;
|
||||
// nodes[i].x = Math.random() * 1000;
|
||||
// nodes[i].y = Math.random() * 1000;
|
||||
// }
|
||||
// for (let i = 0; i < esize; i += 1) {
|
||||
// let node1, node2;
|
||||
// for (let j = 0; j < size; j += 1) {
|
||||
// if (nodes[j].id === edges[i].source) {
|
||||
// node1 = nodes[j];
|
||||
// } else if (nodes[j].id === edges[i].target) {
|
||||
// node2 = nodes[j];
|
||||
// }
|
||||
// }
|
||||
// // const node1 = graph.find(edges[i].source).getModel();
|
||||
// // const node2 = graph.find(edges[i].target).getModel();
|
||||
// nodes[node1.index].degree += 1;
|
||||
// nodes[node2.index].degree += 1;
|
||||
// }
|
||||
|
||||
// const kr_prime = 100;
|
||||
// let iter = max_iteration;
|
||||
// const prevo_iter = 50;
|
||||
// let Forces = [];
|
||||
// const pre_Forces = [];
|
||||
// for (let i = 0; i < size; i += 1) {
|
||||
// Forces[2 * i] = 0;
|
||||
// Forces[2 * i + 1] = 0;
|
||||
|
||||
// if (barnes_hut) {
|
||||
// let params = { id: i, rx: nodes[i].x, ry: nodes[i].y, mass: 1, G: kr, degree: nodes[i].degree };
|
||||
// bodies[i] = new Body(params);
|
||||
// params = null;
|
||||
// }
|
||||
// }
|
||||
|
||||
// do {
|
||||
// for (let i = 0; i < size; i += 1) {
|
||||
// pre_Forces[2 * i] = Forces[2 * i];
|
||||
// pre_Forces[2 * i + 1] = Forces[2 * i + 1];
|
||||
// Forces[2 * i] = 0;
|
||||
// Forces[2 * i + 1] = 0;
|
||||
// }
|
||||
// // attractive forces, existing on every actual edge
|
||||
// Forces = this.getAttrForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, widths);
|
||||
|
||||
// // repulsive forces and Gravity, existing on every node pair
|
||||
// // if prev_overlapping, using the no-optimized method in the last prevo_iter instead.
|
||||
// if (barnes_hut && ((prev_overlapping && iter > prevo_iter) || !prev_overlapping)) {
|
||||
// Forces = this.getOptRepGraForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, center, bodies);
|
||||
// } else {
|
||||
// Forces = this.getRepGraForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, center, widths);
|
||||
// }
|
||||
|
||||
// // update the positions
|
||||
// const res = this.updatePos(size, nodes, Forces, pre_Forces, SG, ks, ksmax, tao);
|
||||
// nodes = res[0];
|
||||
// SG = res[1];
|
||||
// iter -= 1;
|
||||
// } while (iter > 0);
|
||||
// }
|
||||
// console.log(nodes);
|
||||
// self.postMessage(nodes);
|
||||
|
||||
// getAttrForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, widths) {
|
||||
// for (let i = 0; i < esize; i += 1) {
|
||||
// // const source_node = graph.find(edges[i].source).getModel();
|
||||
// // const target_node = graph.find(edges[i].target).getModel();
|
||||
// const source_node, target_node;
|
||||
// const source_idx, target_idx;
|
||||
// for (let j = 0; j < size; j += 1) {
|
||||
// if (nodes[j].id === edges[i].source) {
|
||||
// source_node = nodes[j];
|
||||
// source_idx = j;
|
||||
// } else if (nodes[j].id === edges[i].target) {
|
||||
// target_node = nodes[j];
|
||||
// target_idx = j;
|
||||
// }
|
||||
// }
|
||||
// let dir = [ target_node.x - source_node.x, target_node.y - source_node.y ];
|
||||
// let eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
// eucli_dis = eucli_dis < 0.0001 ? 0.0001 : eucli_dis;
|
||||
// dir[0] = dir[0] / eucli_dis;
|
||||
// dir[1] = dir[1] / eucli_dis;
|
||||
// // the force
|
||||
// if (prev_overlapping && iter < prevo_iter) eucli_dis = eucli_dis - widths[source_idx] - widths[target_idx] ;
|
||||
// let Fa1 = eucli_dis;
|
||||
// let Fa2 = Fa1;
|
||||
// if (mode === 'linlog') {
|
||||
// Fa1 = Math.log(1 + eucli_dis);
|
||||
// Fa2 = Fa1;
|
||||
// }
|
||||
// if (dissuade_hubs) {
|
||||
// Fa1 = eucli_dis / source_node.degree;
|
||||
// Fa2 = eucli_dis / target_node.degree;
|
||||
// }
|
||||
// if (prev_overlapping && iter < prevo_iter && eucli_dis <= 0) {
|
||||
// Fa1 = 0;
|
||||
// Fa2 = 0;
|
||||
// } else if (prev_overlapping && iter < prevo_iter && eucli_dis > 0) {
|
||||
// Fa1 = eucli_dis;
|
||||
// Fa2 = eucli_dis;
|
||||
// }
|
||||
// Forces[2 * source_node.index] += Fa1 * dir[0];
|
||||
// Forces[2 * target_node.index] -= Fa2 * dir[0];
|
||||
// Forces[2 * source_node.index + 1] += Fa1 * dir[1];
|
||||
// Forces[2 * target_node.index + 1] -= Fa2 * dir[1];
|
||||
// dir = null;
|
||||
// }
|
||||
// return Forces;
|
||||
// }
|
||||
|
||||
// getRepGraForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, center, widths) {
|
||||
// for (let i = 0; i < size; i += 1) {
|
||||
// for (let j = i + 1; j < size; j += 1) {
|
||||
// let dir = [ nodes[j].x - nodes[i].x, nodes[j].y - nodes[i].y ];
|
||||
// let eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
// eucli_dis = eucli_dis < 0.0001 ? 0.0001 : eucli_dis;
|
||||
// dir[0] = dir[0] / eucli_dis;
|
||||
// dir[1] = dir[1] / eucli_dis;
|
||||
|
||||
// if (prev_overlapping && iter < prevo_iter) eucli_dis = eucli_dis - whidths[i] - widths[j];
|
||||
|
||||
// let Fr = kr * (nodes[i].degree + 1) * (nodes[j].degree + 1) / eucli_dis;
|
||||
|
||||
// if (prev_overlapping && iter < prevo_iter && eucli_dis < 0) {
|
||||
// Fr = kr_prime * (nodes[i].degree + 1) * (nodes[j].degree + 1);
|
||||
// } else if (prev_overlapping && iter < prevo_iter && eucli_dis === 0) {
|
||||
// Fr = 0;
|
||||
// } else if (prev_overlapping && iter < prevo_iter && eucli_dis > 0) {
|
||||
// Fr = kr * (nodes[i].degree + 1) * (nodes[j].degree + 1) / eucli_dis;
|
||||
// }
|
||||
// Forces[2 * i] -= Fr * dir[0];
|
||||
// Forces[2 * j] += Fr * dir[0];
|
||||
// Forces[2 * i + 1] -= Fr * dir[1];
|
||||
// Forces[2 * j + 1] += Fr * dir[1];
|
||||
// dir = null;
|
||||
// }
|
||||
|
||||
// // gravity
|
||||
// let dir = [ nodes[i].x - center.x, nodes[i].y - center.y ];
|
||||
// const eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
// dir[0] = dir[0] / eucli_dis;
|
||||
// dir[1] = dir[1] / eucli_dis;
|
||||
// const Fg = kg * (nodes[i].degree + 1);
|
||||
// Forces[2 * i] -= Fg * dir[0];
|
||||
// Forces[2 * i + 1] -= Fg * dir[1];
|
||||
// dir = null;
|
||||
// }
|
||||
// return Forces;
|
||||
// }
|
||||
// getOptRepGraForces(nodes, edges, size, esize, prev_overlapping, dissuade_hubs, mode, iter, prevo_iter, Forces, kr, kr_prime, kg, ct, bodies) {
|
||||
// let minx = 9e10,
|
||||
// maxx = -9e10,
|
||||
// miny = 9e10,
|
||||
// maxy = -9e10;
|
||||
// for (let i = 0; i < size; i += 1) {
|
||||
// bodies[i].setPos(nodes[i].x, nodes[i].y);
|
||||
// if (nodes[i].x >= maxx) maxx = nodes[i].x;
|
||||
// if (nodes[i].x <= minx) minx = nodes[i].x;
|
||||
// if (nodes[i].y >= maxy) maxy = nodes[i].y;
|
||||
// if (nodes[i].y <= miny) miny = nodes[i].y;
|
||||
// }
|
||||
|
||||
// let width = Math.max(maxx - minx, maxy - miny);
|
||||
|
||||
// let quad_params = { xmid: (maxx + minx) / 2, ymid: (maxy + miny) / 2, length: width, mass_center: ct, mass: size };
|
||||
// let quad = new Quad(quad_params);
|
||||
// let quad_tree = new QuadTree(quad);
|
||||
|
||||
// // build the tree, insert the nodes(quads) into the tree
|
||||
// for (let i = 0; i < size; i += 1) {
|
||||
// if (bodies[i].in(quad)) quad_tree.insert(bodies[i]);
|
||||
// }
|
||||
// // update the repulsive forces and the gravity.
|
||||
// for (let i = 0; i < size; i += 1) {
|
||||
// bodies[i].resetForce();
|
||||
// quad_tree.updateForce(bodies[i]);
|
||||
// Forces[2 * i] -= bodies[i].fx;
|
||||
// Forces[2 * i + 1] -= bodies[i].fy;
|
||||
|
||||
// // gravity
|
||||
// let dir = [ nodes[i].x - ct.x, nodes[i].y - ct.y ];
|
||||
// let eucli_dis = Math.hypot(dir[0], dir[1]);
|
||||
// eucli_dis = eucli_dis < 0.0001 ? 0.0001 : eucli_dis;
|
||||
// dir[0] = dir[0] / eucli_dis;
|
||||
// dir[1] = dir[1] / eucli_dis;
|
||||
// let Fg = kg * (nodes[i].degree + 1);
|
||||
// Forces[2 * i] -= Fg * dir[0];
|
||||
// Forces[2 * i + 1] -= Fg * dir[1];
|
||||
|
||||
// eucli_dis = null;
|
||||
// Fg = null;
|
||||
// dir = null;
|
||||
// }
|
||||
// quad_params = null;
|
||||
// quad = null;
|
||||
// quad_tree = null;
|
||||
// width = null;
|
||||
// return Forces;
|
||||
// }
|
||||
|
||||
// updatePos(size, nodes, Forces, pre_Forces, SG, ks, ksmax, tao) {
|
||||
// let swgns = [];
|
||||
// let trans = [];
|
||||
// // swg(G) and tra(G)
|
||||
// let swgG = 0;
|
||||
// let traG = 0;
|
||||
// for (let i = 0; i < size; i += 1) {
|
||||
// const minus = [ Forces[2 * i] - pre_Forces[2 * i],
|
||||
// Forces[2 * i + 1] - pre_Forces[2 * i + 1]
|
||||
// ];
|
||||
// const minus_norm = Math.hypot(minus[0], minus[1]);
|
||||
// const add = [ Forces[2 * i] + pre_Forces[2 * i],
|
||||
// Forces[2 * i + 1] + pre_Forces[2 * i + 1]
|
||||
// ];
|
||||
// const add_norm = Math.hypot(add[0], add[1]);
|
||||
|
||||
// swgns[i] = minus_norm;
|
||||
// trans[i] = add_norm / 2;
|
||||
|
||||
// swgG += (nodes[i].degree + 1) * swgns[i];
|
||||
// traG += (nodes[i].degree + 1) * trans[i];
|
||||
// }
|
||||
|
||||
// let pre_SG = SG;
|
||||
// SG = tao * traG / swgG;
|
||||
// if (pre_SG !== 0) {
|
||||
// SG = SG > (1.5 * pre_SG) ? (1.5 * pre_SG) : SG;
|
||||
// }
|
||||
// // update the node positions
|
||||
// for (let i = 0; i < size; i += 1) {
|
||||
// let Sn = ks * SG / (1 + SG * Math.sqrt(swgns[i]));
|
||||
// let absForce = Math.hypot(Forces[2 * i], Forces[2 * i + 1]);
|
||||
// absForce = absForce < 0.0001 ? 0.0001 : absForce;
|
||||
// const max = ksmax / absForce;
|
||||
// Sn = Sn > max ? max : Sn;
|
||||
// const Dn_x = Sn * Forces[2 * i];
|
||||
// const Dn_y = Sn * Forces[2 * i + 1];
|
||||
// nodes[i].x += Dn_x;
|
||||
// nodes[i].y += Dn_y;
|
||||
// }
|
||||
// swgns = null;
|
||||
// trans = null;
|
||||
// pre_SG = null;
|
||||
// return [ nodes, SG ];
|
||||
// }
|
Loading…
Reference in New Issue
Block a user