You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
6.0 KiB
185 lines
6.0 KiB
4 weeks ago
|
|
||
|
/*
|
||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||
|
* or more contributor license agreements. See the NOTICE file
|
||
|
* distributed with this work for additional information
|
||
|
* regarding copyright ownership. The ASF licenses this file
|
||
|
* to you under the Apache License, Version 2.0 (the
|
||
|
* "License"); you may not use this file except in compliance
|
||
|
* with the License. You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing,
|
||
|
* software distributed under the License is distributed on an
|
||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||
|
* KIND, either express or implied. See the License for the
|
||
|
* specific language governing permissions and limitations
|
||
|
* under the License.
|
||
|
*/
|
||
|
|
||
|
|
||
|
/**
|
||
|
* AUTO-GENERATED FILE. DO NOT MODIFY.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||
|
* or more contributor license agreements. See the NOTICE file
|
||
|
* distributed with this work for additional information
|
||
|
* regarding copyright ownership. The ASF licenses this file
|
||
|
* to you under the Apache License, Version 2.0 (the
|
||
|
* "License"); you may not use this file except in compliance
|
||
|
* with the License. You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing,
|
||
|
* software distributed under the License is distributed on an
|
||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||
|
* KIND, either express or implied. See the License for the
|
||
|
* specific language governing permissions and limitations
|
||
|
* under the License.
|
||
|
*/
|
||
|
/*
|
||
|
* A third-party license is embedded for some of the code in this file:
|
||
|
* Some formulas were originally copied from "d3.js" with some
|
||
|
* modifications made for this project.
|
||
|
* (See more details in the comment of the method "step" below.)
|
||
|
* The use of the source code of this file is also subject to the terms
|
||
|
* and consitions of the license of "d3.js" (BSD-3Clause, see
|
||
|
* </licenses/LICENSE-d3>).
|
||
|
*/
|
||
|
import * as vec2 from 'zrender/lib/core/vector.js';
|
||
|
var scaleAndAdd = vec2.scaleAndAdd;
|
||
|
// function adjacentNode(n, e) {
|
||
|
// return e.n1 === n ? e.n2 : e.n1;
|
||
|
// }
|
||
|
export function forceLayout(inNodes, inEdges, opts) {
|
||
|
var nodes = inNodes;
|
||
|
var edges = inEdges;
|
||
|
var rect = opts.rect;
|
||
|
var width = rect.width;
|
||
|
var height = rect.height;
|
||
|
var center = [rect.x + width / 2, rect.y + height / 2];
|
||
|
// let scale = opts.scale || 1;
|
||
|
var gravity = opts.gravity == null ? 0.1 : opts.gravity;
|
||
|
// for (let i = 0; i < edges.length; i++) {
|
||
|
// let e = edges[i];
|
||
|
// let n1 = e.n1;
|
||
|
// let n2 = e.n2;
|
||
|
// n1.edges = n1.edges || [];
|
||
|
// n2.edges = n2.edges || [];
|
||
|
// n1.edges.push(e);
|
||
|
// n2.edges.push(e);
|
||
|
// }
|
||
|
// Init position
|
||
|
for (var i = 0; i < nodes.length; i++) {
|
||
|
var n = nodes[i];
|
||
|
if (!n.p) {
|
||
|
n.p = vec2.create(width * (Math.random() - 0.5) + center[0], height * (Math.random() - 0.5) + center[1]);
|
||
|
}
|
||
|
n.pp = vec2.clone(n.p);
|
||
|
n.edges = null;
|
||
|
}
|
||
|
// Formula in 'Graph Drawing by Force-directed Placement'
|
||
|
// let k = scale * Math.sqrt(width * height / nodes.length);
|
||
|
// let k2 = k * k;
|
||
|
var initialFriction = opts.friction == null ? 0.6 : opts.friction;
|
||
|
var friction = initialFriction;
|
||
|
var beforeStepCallback;
|
||
|
var afterStepCallback;
|
||
|
return {
|
||
|
warmUp: function () {
|
||
|
friction = initialFriction * 0.8;
|
||
|
},
|
||
|
setFixed: function (idx) {
|
||
|
nodes[idx].fixed = true;
|
||
|
},
|
||
|
setUnfixed: function (idx) {
|
||
|
nodes[idx].fixed = false;
|
||
|
},
|
||
|
/**
|
||
|
* Before step hook
|
||
|
*/
|
||
|
beforeStep: function (cb) {
|
||
|
beforeStepCallback = cb;
|
||
|
},
|
||
|
/**
|
||
|
* After step hook
|
||
|
*/
|
||
|
afterStep: function (cb) {
|
||
|
afterStepCallback = cb;
|
||
|
},
|
||
|
/**
|
||
|
* Some formulas were originally copied from "d3.js"
|
||
|
* https://github.com/d3/d3/blob/b516d77fb8566b576088e73410437494717ada26/src/layout/force.js
|
||
|
* with some modifications made for this project.
|
||
|
* See the license statement at the head of this file.
|
||
|
*/
|
||
|
step: function (cb) {
|
||
|
beforeStepCallback && beforeStepCallback(nodes, edges);
|
||
|
var v12 = [];
|
||
|
var nLen = nodes.length;
|
||
|
for (var i = 0; i < edges.length; i++) {
|
||
|
var e = edges[i];
|
||
|
if (e.ignoreForceLayout) {
|
||
|
continue;
|
||
|
}
|
||
|
var n1 = e.n1;
|
||
|
var n2 = e.n2;
|
||
|
vec2.sub(v12, n2.p, n1.p);
|
||
|
var d = vec2.len(v12) - e.d;
|
||
|
var w = n2.w / (n1.w + n2.w);
|
||
|
if (isNaN(w)) {
|
||
|
w = 0;
|
||
|
}
|
||
|
vec2.normalize(v12, v12);
|
||
|
!n1.fixed && scaleAndAdd(n1.p, n1.p, v12, w * d * friction);
|
||
|
!n2.fixed && scaleAndAdd(n2.p, n2.p, v12, -(1 - w) * d * friction);
|
||
|
}
|
||
|
// Gravity
|
||
|
for (var i = 0; i < nLen; i++) {
|
||
|
var n = nodes[i];
|
||
|
if (!n.fixed) {
|
||
|
vec2.sub(v12, center, n.p);
|
||
|
// let d = vec2.len(v12);
|
||
|
// vec2.scale(v12, v12, 1 / d);
|
||
|
// let gravityFactor = gravity;
|
||
|
scaleAndAdd(n.p, n.p, v12, gravity * friction);
|
||
|
}
|
||
|
}
|
||
|
// Repulsive
|
||
|
// PENDING
|
||
|
for (var i = 0; i < nLen; i++) {
|
||
|
var n1 = nodes[i];
|
||
|
for (var j = i + 1; j < nLen; j++) {
|
||
|
var n2 = nodes[j];
|
||
|
vec2.sub(v12, n2.p, n1.p);
|
||
|
var d = vec2.len(v12);
|
||
|
if (d === 0) {
|
||
|
// Random repulse
|
||
|
vec2.set(v12, Math.random() - 0.5, Math.random() - 0.5);
|
||
|
d = 1;
|
||
|
}
|
||
|
var repFact = (n1.rep + n2.rep) / d / d;
|
||
|
!n1.fixed && scaleAndAdd(n1.pp, n1.pp, v12, repFact);
|
||
|
!n2.fixed && scaleAndAdd(n2.pp, n2.pp, v12, -repFact);
|
||
|
}
|
||
|
}
|
||
|
var v = [];
|
||
|
for (var i = 0; i < nLen; i++) {
|
||
|
var n = nodes[i];
|
||
|
if (!n.fixed) {
|
||
|
vec2.sub(v, n.p, n.pp);
|
||
|
scaleAndAdd(n.p, n.p, v, friction);
|
||
|
vec2.copy(n.pp, n.p);
|
||
|
}
|
||
|
}
|
||
|
friction = friction * 0.992;
|
||
|
var finished = friction < 0.01;
|
||
|
afterStepCallback && afterStepCallback(nodes, edges, finished);
|
||
|
cb && cb(finished);
|
||
|
}
|
||
|
};
|
||
|
}
|