diff --git a/kcui/README.md b/kcui/README.md
new file mode 100644
index 0000000..5c4d29f
--- /dev/null
+++ b/kcui/README.md
@@ -0,0 +1,24 @@
+# testvue
+
+## Project setup
+```
+npm install
+```
+
+### Compiles and hot-reloads for development
+```
+npm run serve
+```
+
+### Compiles and minifies for production
+```
+npm run build
+```
+
+### Lints and fixes files
+```
+npm run lint
+```
+
+### Customize configuration
+See [Configuration Reference](https://cli.vuejs.org/config/).
diff --git a/kcui/babel.config.js b/kcui/babel.config.js
new file mode 100644
index 0000000..e955840
--- /dev/null
+++ b/kcui/babel.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+ presets: [
+ '@vue/cli-plugin-babel/preset'
+ ]
+}
diff --git a/kcui/jsconfig.json b/kcui/jsconfig.json
new file mode 100644
index 0000000..4aafc5f
--- /dev/null
+++ b/kcui/jsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "module": "esnext",
+ "baseUrl": "./",
+ "moduleResolution": "node",
+ "paths": {
+ "@/*": [
+ "src/*"
+ ]
+ },
+ "lib": [
+ "esnext",
+ "dom",
+ "dom.iterable",
+ "scripthost"
+ ]
+ }
+}
diff --git a/kcui/package.json b/kcui/package.json
new file mode 100644
index 0000000..4761c79
--- /dev/null
+++ b/kcui/package.json
@@ -0,0 +1,47 @@
+{
+ "name": "testvue",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "serve": "vue-cli-service serve",
+ "build": "vue-cli-service build",
+ "lint": "vue-cli-service lint"
+ },
+ "dependencies": {
+ "axios": "^1.7.9",
+ "core-js": "^3.8.3",
+ "element-ui": "^2.15.14",
+ "js-cookie": "^3.0.5",
+ "vue": "^2.6.14",
+ "vue-router": "^3.5.1"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.12.16",
+ "@babel/eslint-parser": "^7.12.16",
+ "@vue/cli-plugin-babel": "~5.0.0",
+ "@vue/cli-plugin-eslint": "~5.0.0",
+ "@vue/cli-service": "~5.0.0",
+ "eslint": "^7.32.0",
+ "eslint-plugin-vue": "^8.0.3",
+ "vue-template-compiler": "^2.6.14"
+ },
+ "eslintConfig": {
+ "root": true,
+ "env": {
+ "node": true
+ },
+ "extends": [
+ "plugin:vue/essential",
+ "eslint:recommended"
+ ],
+ "parserOptions": {
+ "parser": "@babel/eslint-parser"
+ },
+ "rules": {}
+ },
+ "browserslist": [
+ "> 1%",
+ "last 2 versions",
+ "not dead"
+ ]
+}
diff --git a/kcui/public/favicon.ico b/kcui/public/favicon.ico
new file mode 100644
index 0000000..df36fcf
Binary files /dev/null and b/kcui/public/favicon.ico differ
diff --git a/kcui/public/index.html b/kcui/public/index.html
new file mode 100644
index 0000000..3e5a139
--- /dev/null
+++ b/kcui/public/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+ <%= htmlWebpackPlugin.options.title %>
+
+
+
+
+
+
+
diff --git a/kcui/src/App.vue b/kcui/src/App.vue
new file mode 100644
index 0000000..51165bd
--- /dev/null
+++ b/kcui/src/App.vue
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
diff --git a/kcui/src/api/login.js b/kcui/src/api/login.js
new file mode 100644
index 0000000..02d4156
--- /dev/null
+++ b/kcui/src/api/login.js
@@ -0,0 +1,34 @@
+import request from "@/utils/request";
+
+// 登录方法
+export function userLogin() {
+ return request({
+ url: '/user/doLogin',
+ method: 'get',
+ })
+}
+
+
+export function test() {
+ return request({
+ url: '/user/test',
+ method: 'get',
+ })
+}
+
+
+//获取图谱数据
+// export function getgraphInfo(data) {
+// return request({
+// url: '/user/getDomainGraphTest',
+// method: 'post',
+// data: data
+// })
+// }
+export function getgraphInfo(data) {
+ return request({
+ url: '/graph/getDomainGraphTest',
+ method: 'post',
+ data: data
+ })
+}
diff --git a/kcui/src/api/upload.js b/kcui/src/api/upload.js
new file mode 100644
index 0000000..922d0b6
--- /dev/null
+++ b/kcui/src/api/upload.js
@@ -0,0 +1,10 @@
+//import axios from '../axios'
+import request from '@/utils/request';
+
+export const uploadInfo = (params) => {
+ return request({
+ url: '/api/updateload/upload',
+ method: 'post',
+ data: params,
+ });
+};
diff --git a/kcui/src/assets/defaultConfig.js b/kcui/src/assets/defaultConfig.js
new file mode 100644
index 0000000..070c553
--- /dev/null
+++ b/kcui/src/assets/defaultConfig.js
@@ -0,0 +1,30 @@
+export const config = {
+ background:'40,47,183',
+ node: { //节点的默认配置
+ label: { //标签配置
+ show: false, //是否显示
+ color: '20,20,20', //字体颜色
+ font: 'normal 30px Arial', //字体大小及类型
+ textPosition: 'Bottom_Center' //文字位置 Top_Center,Bottom_Center,Middle_Right,Middle_Center
+ },
+ shape: 'circle',
+ showLabel:false,
+ },
+ link: { //连线的默认配置
+ label: { //连线标签
+ show: true, //是否显示
+ color: '255,255,255', //字体颜色
+ font: 'normal 13px Arial', //字体大小及类型
+ //background:'220,220,220' //标签背景色
+ },
+ lineType: 'direct', //连线类型,direct,curver,vlink,hlink,vbezier,hbezier,bezier
+ colorType: 'defined', //连线颜色类型 source:继承source颜色,target:继承target颜色 both:用双边颜色,defined:自定义
+ alpha: 1, // 连线透明度
+ showArrow: true, //显示连线箭头
+ },
+ lineColor:'202,202,202',
+ layerName:'frDirect',
+
+ wheelZoom: 0.8, //开启鼠标滚轮缩放
+ highLightNeiber: false //相邻节点高亮开关
+}
diff --git a/kcui/src/assets/js/graphvis.layout.min.js b/kcui/src/assets/js/graphvis.layout.min.js
new file mode 100644
index 0000000..a4e7714
--- /dev/null
+++ b/kcui/src/assets/js/graphvis.layout.min.js
@@ -0,0 +1,4639 @@
+/* eslint-disable */
+(function () {
+ var ARFLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.neighborAttraction = 3.0;
+ this.attraction = 0.03;
+ this.forceScale = 0.0;
+ this.deltaT = 5.0;
+ this.forceCutoff = 10.0;
+ this.neighbers = {};
+ this.inited = false;
+ };
+ ARFLayout.prototype.getConfig = function () {
+ return [
+ { label: "邻点引力", neighborAttraction: 8.0 },
+ { label: "引力", attraction: 0.05 },
+ { label: "力缩放系数", forceScale: 8.0 },
+ ];
+ };
+ ARFLayout.prototype.resetConfig = function (layoutConfig) {
+ var _self = this;
+ if (layoutConfig) {
+ this.neighborAttraction =
+ Number(layoutConfig["neighborAttraction"]) || 8.0;
+ this.attraction = Number(layoutConfig["attraction"]) || 0.05;
+ this.forceScale = Number(layoutConfig["forceScale"]) || 8.0;
+ this.neighbers = {};
+ _self.nodes.forEach(function (n) {
+ n.degree = (n.inLinks || []).length + (n.outLinks || []).length;
+ });
+ }
+ this.inited = true;
+ };
+ ARFLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ ARFLayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ ARFLayout.prototype.initAlgo = function () {
+ var _self = this;
+ _self.neighborAttraction = 8.0;
+ _self.attraction = 0.12;
+ _self.forceScale = 5.0;
+ _self.deltaT = 5.0;
+ _self.forceCutoff = 10.0;
+ _self.nodes.forEach(function (n) {
+ var inLinks = n.inLinks || [];
+ var outLinks = n.outLinks || [];
+ n.degree = inLinks.length + outLinks.length;
+ });
+ this.inited = true;
+ };
+ ARFLayout.prototype.goAlgo = function () {
+ var _self = this;
+ var minX = Infinity,
+ minY = Infinity;
+ _self.nodes.forEach(function (node) {
+ var f = _self.getForceforNode(node);
+ var degree = node.degree;
+ var deltaIndividual =
+ degree <= 1 ? _self.deltaT : _self.deltaT / Math.pow(degree, 0.4);
+ f = { x: f.x * deltaIndividual, y: f.y * deltaIndividual };
+ node.x += f.x;
+ node.y += f.y;
+ minX = Math.min(minX, node.x);
+ minY = Math.min(minY, node.y);
+ });
+ _self.nodes.forEach(function (node) {
+ node.x += 100 - minX;
+ node.y += 100 - minY;
+ });
+ };
+ ARFLayout.prototype.getForceforNode = function (node) {
+ var _self = this;
+ var numNodes = _self.nodes.length;
+ var mDot = { x: 0, y: 0 };
+ if (node.x == 0 && node.y == 0) {
+ return mDot;
+ }
+ _self.nodes.forEach(function (n) {
+ if (node.id != n.id && (n.x != 0 || n.y != 0)) {
+ var tempX = n.x - node.x;
+ var tempY = n.y - node.y;
+ if (tempX == 0 && tempY == 0) {
+ tempX = 50;
+ tempY = 50;
+ }
+ var multiplier = 1.0;
+ if (_self.isAdjacent(node, n)) {
+ multiplier = _self.neighborAttraction;
+ }
+ multiplier = multiplier * (_self.attraction / Math.sqrt(numNodes));
+ mDot = {
+ x: mDot.x + tempX * multiplier,
+ y: mDot.y + tempY * multiplier,
+ };
+ multiplier = 1.0 / Math.sqrt(tempX * tempX + tempY * tempY);
+ mDot = {
+ x: mDot.x - tempX * multiplier * _self.forceScale,
+ y: mDot.y - tempY * multiplier * _self.forceScale,
+ };
+ }
+ });
+ var distance = _self.distance(0.0, 0.0, mDot.x, mDot.y);
+ if (distance > _self.forceCutoff) {
+ var mult = _self.forceCutoff / distance;
+ mDot = { x: mDot.x * mult, y: mDot.y * mult };
+ }
+ return mDot;
+ };
+ ARFLayout.prototype.getDegree = function (node) {
+ return (node.inLinks || []).length + (node.outLinks || []).length;
+ };
+ ARFLayout.prototype.isAdjacent = function (node, otherNode) {
+ var neighbers = [];
+ (node.inLinks || []).forEach(function (l) {
+ neighbers.push(l.source);
+ });
+ (node.outLinks || []).forEach(function (l) {
+ neighbers.push(l.target);
+ });
+ var flag = false;
+ neighbers.forEach(function (n) {
+ if (n.id == otherNode.id) {
+ flag = true;
+ }
+ });
+ };
+ ARFLayout.prototype.distance = function (px, py, x, y) {
+ px -= x;
+ py -= y;
+ return Math.sqrt(px * px + py * py);
+ };
+ var CircleLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.diameter = 500;
+ this.boolfixeddiameter = false;
+ this.boolTransition = true;
+ this.cumethod = "auto";
+ this.scale = 1.2;
+ this.TWO_PI = Math.PI * 2;
+ this.center = [0, 0];
+ this.intSteps = 50;
+ this.inited = false;
+ };
+ CircleLayout.prototype.getConfig = function () {
+ return [
+ {
+ label: "直径计算",
+ cumethod: [
+ { label: "自动", value: "auto" },
+ { label: "指定", value: "metal" },
+ ],
+ },
+ { label: "直径大小", diameter: 500 },
+ { label: "中心位置", center: [0, 0] },
+ ];
+ };
+ CircleLayout.prototype.resetConfig = function (layoutConfig) {
+ this.diameter = Number(layoutConfig["diameter"]) || 500;
+ this.cumethod = layoutConfig["cumethod"] || "auto";
+ this.center = layoutConfig["center"] || [0, 0];
+ if (this.cumethod == "auto") {
+ this.boolfixeddiameter = false;
+ } else {
+ this.boolfixeddiameter = true;
+ }
+ this.initAlgo();
+ };
+ CircleLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ CircleLayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ CircleLayout.prototype.initAlgo = function () {
+ var _self = this;
+ var nodes = _self.nodes;
+ var nodeCount = nodes.length;
+ var nodeCoords = [];
+ var tempcirc = 0.0;
+ var temdiameter = 0.0;
+ var index = 0;
+ var noderadius = 0.0;
+ var theta = _self.TWO_PI / nodeCount;
+ var lasttheta = 0.0;
+ nodes = nodes.sort(function (n1, n2) {
+ var x = (n1.inLinks || []).length + (n1.outLinks || []).length;
+ var y = (n2.inLinks || []).length + (n2.outLinks || []).length;
+ if (x > y) {
+ return -1;
+ } else if (x < y) {
+ return 1;
+ } else {
+ return 0;
+ }
+ });
+ if (!_self.boolfixeddiameter) {
+ for (var i = 0; i < nodeCount; i++) {
+ var n = nodes[i];
+ tempcirc += n.scaleX * n.radius * 2 * 1.2;
+ }
+ tempcirc *= _self.scale;
+ temdiameter = tempcirc / Math.PI;
+ theta = _self.TWO_PI / tempcirc;
+ } else {
+ temdiameter = _self.diameter;
+ }
+ var radius = temdiameter / 2;
+ for (var i = 0; i < nodeCount; i++) {
+ var n = nodes[i];
+ if (!_self.boolfixeddiameter) {
+ noderadius = n.scaleX * n.radius * 2;
+ var noderadian = theta * noderadius * _self.scale;
+ nodeCoords = _self.cartCoors(radius, 1, lasttheta + noderadian);
+ lasttheta += noderadius * 1.2 * theta * _self.scale;
+ } else {
+ nodeCoords = _self.cartCoors(radius, index, theta);
+ }
+ var posData = _self.newLayoutData();
+ posData.finishx = nodeCoords[0];
+ posData.finishy = nodeCoords[1];
+ posData.xdistance = (1.0 / _self.intSteps) * (nodeCoords[0] - n.x);
+ posData.ydistance = (1.0 / _self.intSteps) * (nodeCoords[1] - n.y);
+ n.layoutData = posData;
+ index++;
+ }
+ this.inited = true;
+ };
+ CircleLayout.prototype.cartCoors = function (radius, whichInt, theta) {
+ var coOrds = [];
+ coOrds[0] = this.center[0] + radius * Math.cos(theta * whichInt);
+ coOrds[1] = this.center[1] + radius * Math.sin(theta * whichInt);
+ return coOrds;
+ };
+ CircleLayout.prototype.goAlgo = function () {
+ var _self = this;
+ var position = null;
+ var nodes = _self.nodes;
+ var length = nodes.length;
+ for (var i = 0; i < length; i++) {
+ var n = nodes[i];
+ position = n.layoutData;
+ if (position == null) {
+ continue;
+ }
+ if (_self.boolTransition) {
+ var currentDistance = Math.abs(n.x - position.finishx);
+ var nextDistance = Math.abs(
+ n.x + position.xdistance - position.finishx,
+ );
+ if (nextDistance < currentDistance) {
+ n.x += position.xdistance;
+ } else {
+ n.x = position.finishx;
+ }
+ currentDistance = Math.abs(n.y - position.finishy);
+ nextDistance = Math.abs(n.y + position.ydistance - position.finishy);
+ if (nextDistance < currentDistance) {
+ n.y += position.ydistance;
+ } else {
+ n.y = position.finishy;
+ }
+ if (n.x == position.finishx && n.y == position.finishy) {
+ n.layoutData = null;
+ }
+ } else {
+ n.x = position.finishx;
+ n.y = position.finishy;
+ n.layoutData = null;
+ }
+ }
+ };
+ var DualCircleLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.highdegreeoutside = false;
+ this.secondarynodecount = 15;
+ this.boolNoOverlap = true;
+ this.boolTransition = true;
+ this.TWO_PI = Math.PI * 2;
+ this.intSteps = 50;
+ this.inited = false;
+ };
+ DualCircleLayout.prototype.getConfig = function () {
+ return [
+ {
+ label: "分布位置",
+ position: [
+ { label: "环内部", value: "inside" },
+ { label: "环外部", value: "outside" },
+ ],
+ },
+ { label: "核心数", secondarynodecount: 15 },
+ ];
+ };
+ DualCircleLayout.prototype.resetConfig = function (layoutConfig) {
+ this.secondarynodecount = Number(layoutConfig["secondarynodecount"]) || 15;
+ this.position = layoutConfig["position"] || "inside";
+ if (this.position == "inside") {
+ this.highdegreeoutside = false;
+ } else {
+ this.highdegreeoutside = true;
+ }
+ this.initAlgo();
+ };
+ DualCircleLayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ DualCircleLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ DualCircleLayout.prototype.initAlgo = function () {
+ var _self = this;
+ var nodes = _self.nodes;
+ var nodeCounts = nodes.length;
+ var nodeCoords = [];
+ var tmpsecondarycirc = 0,
+ tmpprimarycirc = 0;
+ var lasttheta = 0,
+ secondary_theta = 0,
+ correct_theta = 0;
+ var primary_scale = 1,
+ secondry_scale = 1;
+ if (_self.secondarynodecount > nodeCounts) {
+ _self.secondarynodecount = 1;
+ }
+ nodes = nodes.sort(function (n1, n2) {
+ var x = (n1.inLinks || []).length + (n1.outLinks || []).length;
+ var y = (n2.inLinks || []).length + (n2.outLinks || []).length;
+ if (x > y) {
+ return -1;
+ } else if (x < y) {
+ return 1;
+ } else {
+ return 0;
+ }
+ });
+ for (var i = 0; i < nodeCounts; i++) {
+ var n = nodes[i];
+ var noderadius = n.scaleX * n.radius;
+ if (i < _self.secondarynodecount) {
+ tmpsecondarycirc += noderadius * 2.0;
+ } else {
+ tmpprimarycirc += noderadius * 2.0;
+ }
+ }
+ var circum_ratio = tmpprimarycirc / tmpsecondarycirc;
+ if (circum_ratio < 2) {
+ primary_scale = 2 / circum_ratio;
+ tmpprimarycirc = 2 * tmpsecondarycirc;
+ }
+ if (_self.highdegreeoutside) {
+ secondry_scale = (2 * tmpprimarycirc) / tmpsecondarycirc;
+ tmpsecondarycirc = tmpprimarycirc * 2;
+ } else {
+ secondry_scale = tmpprimarycirc / (2 * tmpsecondarycirc);
+ tmpsecondarycirc = tmpprimarycirc / 2;
+ }
+ tmpprimarycirc *= 1.2;
+ primary_theta = _self.TWO_PI / tmpprimarycirc;
+ var primaryradius = tmpprimarycirc / Math.PI / 2;
+ tmpsecondarycirc *= 1.2;
+ secondary_theta = _self.TWO_PI / tmpsecondarycirc;
+ var secondaryradius = tmpsecondarycirc / Math.PI / 2;
+ for (var i = 0; i < nodeCounts; i++) {
+ var n = nodes[i];
+ var noderadius = n.scaleX * n.radius;
+ if (i < _self.secondarynodecount) {
+ if (secondry_scale > 2) {
+ noderadius =
+ tmpsecondarycirc /
+ (2 * _self.secondarynodecount * secondry_scale * 1.2);
+ }
+ var noderadian = secondary_theta * noderadius * 1.2 * secondry_scale;
+ if (i == 0) {
+ correct_theta = noderadian;
+ }
+ nodeCoords = _self.cartCoors(
+ secondaryradius,
+ 1,
+ lasttheta + noderadian - correct_theta,
+ );
+ lasttheta += noderadius * 2 * secondary_theta * 1.2 * secondry_scale;
+ } else {
+ var noderadian = primary_theta * noderadius * 1.2 * primary_scale;
+ if (i == _self.secondarynodecount) {
+ lasttheta = 0;
+ correct_theta = noderadian;
+ }
+ nodeCoords = _self.cartCoors(
+ primaryradius,
+ 1,
+ lasttheta + noderadian - correct_theta,
+ );
+ lasttheta += noderadius * 2 * primary_theta * 1.2 * primary_scale;
+ }
+ var posData = _self.newLayoutData();
+ posData.finishx = nodeCoords[0];
+ posData.finishy = nodeCoords[1];
+ posData.xdistance = (1.0 / _self.intSteps) * (nodeCoords[0] - n.x);
+ posData.ydistance = (1.0 / _self.intSteps) * (nodeCoords[1] - n.y);
+ n.layoutData = posData;
+ }
+ this.inited = true;
+ };
+ DualCircleLayout.prototype.goAlgo = function () {
+ var _self = this;
+ var position = null;
+ var nodes = _self.nodes;
+ var length = nodes.length;
+ for (var i = 0; i < length; i++) {
+ var n = nodes[i];
+ position = n.layoutData;
+ if (position == null) {
+ continue;
+ }
+ if (_self.boolTransition) {
+ var currentDistance = Math.abs(n.x - position.finishx);
+ var nextDistance = Math.abs(
+ n.x + position.xdistance - position.finishx,
+ );
+ if (nextDistance < currentDistance) {
+ n.x += position.xdistance;
+ } else {
+ n.x = position.finishx;
+ }
+ currentDistance = Math.abs(n.y - position.finishy);
+ nextDistance = Math.abs(n.y + position.ydistance - position.finishy);
+ if (nextDistance < currentDistance) {
+ n.y += position.ydistance;
+ } else {
+ n.y = position.finishy;
+ }
+ if (n.x == position.finishx && n.y == position.finishy) {
+ n.layoutData = null;
+ }
+ } else {
+ n.x = position.finishx;
+ n.y = position.finishy;
+ n.layoutData = null;
+ }
+ }
+ };
+ DualCircleLayout.prototype.cartCoors = function (radius, whichInt, theta) {
+ var coOrds = [];
+ coOrds[0] = radius * Math.cos(theta * whichInt + Math.PI / 2);
+ coOrds[1] = radius * Math.sin(theta * whichInt + Math.PI / 2);
+ return coOrds;
+ };
+ var LayerLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.outCircleNodes = 11;
+ this.layerDistance = 30;
+ this.boolTransition = true;
+ this.intSteps = 50;
+ this.inited = false;
+ };
+ LayerLayout.prototype.getConfig = function () {
+ return [
+ { label: "外层点数", outCircleNodes: 11 },
+ { label: "层间距", layerDistance: 30 },
+ ];
+ };
+ LayerLayout.prototype.resetConfig = function (layoutConfig) {
+ this.outCircleNodes = Number(layoutConfig["outCircleNodes"]) || 11;
+ this.layerDistance = Number(layoutConfig["layerDistance"]) || 30;
+ this.initAlgo();
+ };
+ LayerLayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ LayerLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ LayerLayout.prototype.initAlgo = function () {
+ var _self = this;
+ var nodes = _self.nodes;
+ var nodeCount = nodes.length;
+ var innerCircleRaduis = 0,
+ nextLayerRoundLong = 0,
+ currentRoundLong = 0;
+ var maxTheta = 0,
+ theta = 0;
+ nodes = nodes.sort(function (n1, n2) {
+ var x = (n1.inLinks || []).length + (n1.outLinks || []).length;
+ var y = (n2.inLinks || []).length + (n2.outLinks || []).length;
+ if (x < y) {
+ return -1;
+ } else if (x > y) {
+ return 1;
+ } else {
+ return 0;
+ }
+ });
+ if (_self.outCircleNodes > nodeCount) {
+ _self.outCircleNodes = 0;
+ }
+ for (var i = 0; i < nodeCount; i++) {
+ var node = nodes[i];
+ currentRoundLong += node.radius * node.scaleX;
+ if (currentRoundLong > nextLayerRoundLong) {
+ nextLayerNodeRaduis = node.radius * node.scaleX;
+ nextCircleRaduis =
+ innerCircleRaduis + _self.layerDistance + nextLayerNodeRaduis;
+ nextLayerRoundLong = 2 * Math.PI * nextCircleRaduis;
+ innerCircleRaduis =
+ innerCircleRaduis + _self.layerDistance + node.radius * node.scaleX;
+ theta = 1.0 / nextCircleRaduis;
+ maxTheta = 0;
+ currentRoundLong = node.radius * node.scaleX;
+ }
+ var thisAngle = 0;
+ if (i < nodeCount - _self.outCircleNodes) {
+ thisAngle = theta * node.radius * node.scaleX;
+ } else {
+ nextCircleRaduis =
+ innerCircleRaduis + _self.layerDistance + nextLayerNodeRaduis;
+ thisAngle = (2 * Math.PI) / _self.outCircleNodes;
+ }
+ maxTheta += thisAngle;
+ var posData = _self.newLayoutData();
+ posData.finishx = nextCircleRaduis * 2.4 * Math.cos(maxTheta + Math.PI);
+ posData.finishy = nextCircleRaduis * 2.4 * Math.sin(maxTheta + Math.PI);
+ posData.xdistance = (1.0 / _self.intSteps) * (posData.finishx - node.x);
+ posData.ydistance = (1.0 / _self.intSteps) * (posData.finishy - node.y);
+ node.layoutData = posData;
+ }
+ this.inited = true;
+ };
+ LayerLayout.prototype.goAlgo = function () {
+ var _self = this;
+ var position = null;
+ var nodes = _self.nodes;
+ var length = nodes.length;
+ for (var i = 0; i < length; i++) {
+ var n = nodes[i];
+ position = n.layoutData;
+ if (position == null) {
+ continue;
+ }
+ if (_self.boolTransition) {
+ var currentDistance = Math.abs(n.x - position.finishx);
+ var nextDistance = Math.abs(
+ n.x + position.xdistance - position.finishx,
+ );
+ if (nextDistance < currentDistance) {
+ n.x += position.xdistance;
+ } else {
+ n.x = position.finishx;
+ }
+ currentDistance = Math.abs(n.y - position.finishy);
+ nextDistance = Math.abs(n.y + position.ydistance - position.finishy);
+ if (nextDistance < currentDistance) {
+ n.y += position.ydistance;
+ } else {
+ n.y = position.finishy;
+ }
+ if (n.x == position.finishx && n.y == position.finishy) {
+ n.layoutData = null;
+ }
+ } else {
+ n.x = position.finishx;
+ n.y = position.finishy;
+ n.layoutData = null;
+ }
+ }
+ };
+ var FRlayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.AREA_MULTIPLICATOR = 10000;
+ this.area = 800;
+ this.gravity = 1.2;
+ this.SPEED_DIVISOR = 800.0;
+ this.speed = 10;
+ this.inited = false;
+ };
+ FRlayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ dx: 0.0,
+ dy: 0.0,
+ old_dx: 0.0,
+ old_dy: 0.0,
+ freeze: 0.0,
+ };
+ return layoutData;
+ };
+ FRlayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ FRlayout.prototype.getConfig = function () {
+ return [
+ { label: "区域大小", area: 500 },
+ { label: "重力", gravity: 2.0 },
+ ];
+ };
+ FRlayout.prototype.resetConfig = function (layoutConfig) {
+ var _self = this;
+ if (layoutConfig) {
+ this.area = Number(layoutConfig["area"]) || 500;
+ this.gravity = Number(layoutConfig["gravity"]) || 1.5;
+ this.nodes.forEach(function (n) {
+ n.layoutData = _self.newLayoutData();
+ });
+ }
+ this.inited = true;
+ };
+ FRlayout.prototype.initAlgo = function () {
+ var _self = this;
+ _self.area = _self.nodes.length / 2;
+ _self.nodes.forEach(function (n) {
+ n.layoutData = _self.newLayoutData();
+ });
+ this.inited = true;
+ };
+ FRlayout.prototype.goAlgo = function () {
+ var _self = this;
+ var nodes = _self.nodes;
+ var nodeCount = nodes.length;
+ var maxDisplace = Math.sqrt(_self.AREA_MULTIPLICATOR * _self.area) / 10.0;
+ var k = Math.sqrt(
+ (_self.AREA_MULTIPLICATOR * _self.area) / (1.0 + nodeCount),
+ );
+ nodes.forEach(function (N1, i) {
+ N1.layoutData.dx = 0;
+ N1.layoutData.dy = 0;
+ nodes.forEach(function (N2, j) {
+ if (i != j) {
+ var xDist = N1.x - N2.x;
+ var yDist = N1.y - N2.y;
+ var dist = Math.sqrt(xDist * xDist + yDist * yDist);
+ if (dist > 0) {
+ var repulsiveF = (k * k) / dist;
+ var layoutData = N1.layoutData;
+ layoutData.dx += (xDist / dist) * repulsiveF;
+ layoutData.dy += (yDist / dist) * repulsiveF;
+ }
+ }
+ });
+ });
+ var links = _self.links;
+ links.forEach(function (E) {
+ var Nf = E.source;
+ var Nt = E.target;
+ var xDist = Nf.x - Nt.x;
+ var yDist = Nf.y - Nt.y;
+ var dist = Math.sqrt(xDist * xDist + yDist * yDist);
+ var attractiveF = (dist * dist) / k;
+ if (dist > 0) {
+ var sourceLayoutData = Nf.layoutData;
+ var targetLayoutData = Nt.layoutData;
+ sourceLayoutData.dx -= (xDist / dist) * attractiveF;
+ sourceLayoutData.dy -= (yDist / dist) * attractiveF;
+ targetLayoutData.dx += (xDist / dist) * attractiveF;
+ targetLayoutData.dy += (yDist / dist) * attractiveF;
+ }
+ });
+ nodes.forEach(function (n) {
+ var layoutData = n.layoutData;
+ var d = Math.sqrt(n.x * n.x + n.y * n.y);
+ var gf = 0.01 * k * _self.gravity * d;
+ layoutData.dx -= (gf * n.x) / d;
+ layoutData.dy -= (gf * n.y) / d;
+ layoutData.dx *= _self.speed / _self.SPEED_DIVISOR;
+ layoutData.dy *= _self.speed / _self.SPEED_DIVISOR;
+ var dist = Math.sqrt(
+ layoutData.dx * layoutData.dx + layoutData.dy * layoutData.dy,
+ );
+ if (dist > 0) {
+ var limitedDist = Math.min(
+ maxDisplace * (_self.speed / _self.SPEED_DIVISOR),
+ dist,
+ );
+ n.x += (layoutData.dx / dist) * limitedDist;
+ n.y += (layoutData.dy / dist) * limitedDist;
+ }
+ });
+ };
+ var FruchtermanReingoldLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.config = {
+ autoArea: true,
+ area: 1000,
+ gravity: 3,
+ speed: 0.08,
+ iterations: 1000,
+ };
+ this.maxDisplace = 10;
+ this.k = 120.0;
+ this.currentIter = 0;
+ this.inited = false;
+ };
+ FruchtermanReingoldLayout.prototype.getConfig = function () {
+ var self = this;
+ return [
+ { label: "重力", gravity: 0.5 },
+ { label: "边长度", k: self.k },
+ { label: "收敛速度", speed: 0.5 },
+ ];
+ };
+ FruchtermanReingoldLayout.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.nodes.forEach(function (node) {
+ node.fr_x = node.x;
+ node.fr_y = node.y;
+ node.fr = { dx: 0, dy: 0 };
+ });
+ this.config.gravity = Number(layoutConfig["gravity"]) || 0.5;
+ this.config.speed = Number(layoutConfig["speed"]) || 0.08;
+ this.k = Number(layoutConfig["k"]) || 120;
+ this.currentIter = 0;
+ }
+ this.inited = true;
+ };
+ FruchtermanReingoldLayout.prototype.initAlgo = function () {
+ var self = this;
+ var nodesCount = this.nodes.length;
+ self.nodes.forEach(function (node) {
+ node.fr_x = node.x;
+ node.fr_y = node.y;
+ node.fr = { dx: 0, dy: 0 };
+ });
+ self.config.area = self.config.autoArea
+ ? nodesCount * nodesCount
+ : self.config.area;
+ self.maxDisplace = Math.sqrt(self.config.area) / 8;
+ self.k = Math.sqrt(self.config.area / (1 + nodesCount));
+ if (self.maxDisplace < 150) {
+ self.maxDisplace = 150;
+ }
+ if (self.k < 40) {
+ self.k = 40;
+ }
+ self.currentIter = 0;
+ this.inited = true;
+ };
+ FruchtermanReingoldLayout.prototype.runLayout = function () {
+ if (this.currentIter > this.config.iterations) {
+ return;
+ }
+ if (this.inited) {
+ this.goAlgo();
+ this.currentIter++;
+ }
+ };
+ FruchtermanReingoldLayout.prototype.goAlgo = function () {
+ var self = this;
+ var nodes = self.nodes;
+ var links = self.links;
+ var nodesCount = self.nodes.length;
+ for (var i = 0; i < nodesCount; i++) {
+ var n = nodes[i];
+ for (var j = 0; j < nodesCount; j++) {
+ var n2 = nodes[j];
+ if (n.id != n2.id) {
+ var xDist = n.fr_x - n2.fr_x;
+ var yDist = n.fr_y - n2.fr_y;
+ var dist = Math.sqrt(xDist * xDist + yDist * yDist) + 0.01;
+ if (dist > 0) {
+ var repulsiveF = (self.k * self.k) / dist;
+ n.fr.dx += (xDist / dist) * repulsiveF;
+ n.fr.dy += (yDist / dist) * repulsiveF;
+ }
+ }
+ }
+ }
+ var edgesCount = links.length;
+ for (i = 0; i < edgesCount; i++) {
+ var link = links[i];
+ var nSource = link.source;
+ var nTarget = link.target;
+ var xDist = nSource.fr_x - nTarget.fr_x;
+ var yDist = nSource.fr_y - nTarget.fr_y;
+ var dist = Math.sqrt(xDist * xDist + yDist * yDist) + 0.01;
+ var attractiveF = (dist * dist) / self.k;
+ if (dist > 0) {
+ nSource.fr.dx -= (xDist / dist) * attractiveF;
+ nSource.fr.dy -= (yDist / dist) * attractiveF;
+ nTarget.fr.dx += (xDist / dist) * attractiveF;
+ nTarget.fr.dy += (yDist / dist) * attractiveF;
+ }
+ }
+ for (var i = 0; i < nodesCount; i++) {
+ var n = nodes[i];
+ var d = Math.sqrt(n.fr_x * n.fr_x + n.fr_y * n.fr_y);
+ var gf = 0.01 * self.k * self.config.gravity * d;
+ n.fr.dx -= (gf * n.fr_x) / d;
+ n.fr.dy -= (gf * n.fr_y) / d;
+ n.fr.dx *= self.config.speed;
+ n.fr.dy *= self.config.speed;
+ if (!n.fixed) {
+ var xDist = n.fr.dx;
+ var yDist = n.fr.dy;
+ dist = Math.sqrt(xDist * xDist + yDist * yDist);
+ if (dist > 0) {
+ var limitedDist = Math.min(
+ self.maxDisplace * self.config.speed,
+ dist,
+ );
+ n.fr_x += (xDist / dist) * limitedDist;
+ n.fr_y += (yDist / dist) * limitedDist;
+ }
+ }
+ }
+ for (var i = 0; i < nodesCount; i++) {
+ nodes[i].x = nodes[i].fr_x;
+ nodes[i].y = nodes[i].fr_y;
+ }
+ };
+ var GirdLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.xOrigin = 1;
+ this.yOrigin = 1;
+ this.horizontalScale = 60;
+ this.verticalScale = 60;
+ this.horizontal = false;
+ this.center = [100, 100];
+ this.boolTransition = true;
+ this.intSteps = 50;
+ this.inited = false;
+ };
+ GirdLayout.prototype.getConfig = function () {
+ return [
+ { label: "水平间距", horizontalScale: 100 },
+ { label: "垂直间距", verticalScale: 100 },
+ ];
+ };
+ GirdLayout.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.horizontalScale = Number(layoutConfig["horizontalScale"]) || 100;
+ this.verticalScale = Number(layoutConfig["verticalScale"]) || 100;
+ this.center = layoutConfig["center"] || [100, 100];
+ this.initAlgo();
+ }
+ };
+ GirdLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ GirdLayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ GirdLayout.prototype.initAlgo = function () {
+ var _self = this;
+ var nodes = _self.nodes;
+ var nodeCount = nodes.length;
+ var xGridScales = Math.round(Math.sqrt(nodeCount)) + 1;
+ var yGridScales = Math.round(Math.sqrt(nodeCount)) + 1;
+ this.inited = true;
+ nodes = nodes.sort(function (n1, n2) {
+ var x = (n1.inLinks || []).length + (n1.outLinks || []).length;
+ var y = (n2.inLinks || []).length + (n2.outLinks || []).length;
+ if (x > y) {
+ return -1;
+ } else if (x < y) {
+ return 1;
+ } else {
+ return 0;
+ }
+ });
+ var k = 0;
+ for (var i = 0; i < xGridScales; i++) {
+ for (var j = 0; j < yGridScales; j++) {
+ if (k >= nodeCount) {
+ continue;
+ }
+ var tempX, tempY;
+ if (_self.horizontal) {
+ tempX = _self.xGridToScreen(i, j);
+ tempY = _self.yGridToScreen(i, j);
+ } else {
+ tempX = _self.yGridToScreen(i, j);
+ tempY = -_self.xGridToScreen(i, j);
+ }
+ tempX += _self.center[0] - (xGridScales / 2) * _self.horizontalScale;
+ tempY +=
+ _self.center[1] +
+ (yGridScales / 2) * _self.verticalScale -
+ _self.verticalScale;
+ var node = nodes[k++];
+ var posData = _self.newLayoutData();
+ posData.finishx = tempX;
+ posData.finishy = tempY;
+ posData.xdistance = (1.0 / _self.intSteps) * (tempX - node.x);
+ posData.ydistance = (1.0 / _self.intSteps) * (tempY - node.y);
+ node.layoutData = posData;
+ }
+ }
+ };
+ GirdLayout.prototype.goAlgo = function () {
+ var _self = this;
+ var position = null;
+ var nodes = _self.nodes;
+ var length = nodes.length;
+ for (var i = 0; i < length; i++) {
+ var n = nodes[i];
+ position = n.layoutData;
+ if (position == null) {
+ continue;
+ }
+ if (_self.boolTransition) {
+ var currentDistance = Math.abs(n.x - position.finishx);
+ var nextDistance = Math.abs(
+ n.x + position.xdistance - position.finishx,
+ );
+ if (nextDistance < currentDistance) {
+ n.x += position.xdistance;
+ } else {
+ n.x = position.finishx;
+ }
+ currentDistance = Math.abs(n.y - position.finishy);
+ nextDistance = Math.abs(n.y + position.ydistance - position.finishy);
+ if (nextDistance < currentDistance) {
+ n.y += position.ydistance;
+ } else {
+ n.y = position.finishy;
+ }
+ if (n.x == position.finishx && n.y == position.finishy) {
+ n.layoutData = null;
+ }
+ } else {
+ n.x = position.finishx;
+ n.y = position.finishy;
+ n.layoutData = null;
+ }
+ }
+ };
+ GirdLayout.prototype.xGridToScreen = function (xg, yg) {
+ return this.xOrigin + xg * this.horizontalScale;
+ };
+ GirdLayout.prototype.yGridToScreen = function (xg, yg) {
+ return this.yOrigin + yg * this.verticalScale;
+ };
+ var KKLayout = function (_nodes, _links) {
+ this.nodes = _nodes;
+ this.links = _links;
+ this.nodeIds = [];
+ this.VECTOR_D1 = [];
+ this.VECTOR_D2 = [];
+ this.lij = [];
+ this.kij = [];
+ this.tempNodes = [];
+ this.realSize = 3000.0;
+ this.tempSize = 5.0;
+ this.inited = false;
+ };
+ KKLayout.prototype.getConfig = function () {
+ var canvasWidth = this.setCanvasSize(this.nodes.length);
+ return [{ label: "区域大小", realSize: canvasWidth }];
+ };
+ KKLayout.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.realSize = Number(layoutConfig["realSize"]) || 1000;
+ this.initAlgo();
+ }
+ };
+ KKLayout.prototype.runLayout = function () {
+ var i = 0;
+ while (i++ < 100 && this.inited) {
+ this.goAlgo();
+ }
+ };
+ KKLayout.prototype.initAlgo = function () {
+ var _self = this;
+ var nodes = _self.nodes;
+ var nodeCount = nodes.length;
+ this.inited = true;
+ var L0 = _self.tempSize;
+ _self.nodeIds = [];
+ _self.tempNodes = [];
+ _self.VECTOR_D1 = [];
+ _self.VECTOR_D2 = [];
+ _self.lij = [];
+ _self.kij = [];
+ nodes.forEach(function (node) {
+ _self.nodeIds.push(node.id);
+ _self.tempNodes.push({
+ id: node.id,
+ x: node.x / (_self.realSize / _self.tempSize),
+ y: node.y / (_self.realSize / _self.tempSize),
+ });
+ });
+ var lij = [nodeCount];
+ var kij = [nodeCount];
+ var dij = _self.shortPath(nodeCount);
+ var max_dij = _self.getMaxDij(nodeCount, dij);
+ _self.getKijLij(L0, max_dij, dij, kij, lij);
+ var _VECTOR_D1 = [nodeCount];
+ var _VECTOR_D2 = [nodeCount];
+ _self.tempNodes.forEach(function (nodeM, i) {
+ var myD1 = 0.0,
+ myD2 = 0.0;
+ _self.tempNodes.forEach(function (nodeN, j) {
+ if (i != j) {
+ var dx = nodeM.x - nodeN.x;
+ var dy = nodeM.y - nodeN.y;
+ var mi_dist = Math.sqrt(dx * dx + dy * dy);
+ myD1 += kij[i][j] * (dx - (lij[i][j] * dx) / mi_dist);
+ myD2 += kij[i][j] * (dy - (lij[i][j] * dy) / mi_dist);
+ }
+ });
+ _VECTOR_D1[i] = myD1;
+ _VECTOR_D2[i] = myD2;
+ });
+ _self.VECTOR_D1 = _VECTOR_D1;
+ _self.VECTOR_D2 = _VECTOR_D2;
+ _self.lij = lij;
+ _self.kij = kij;
+ };
+ KKLayout.prototype.goAlgo = function () {
+ var _self = this;
+ var nodeCount = _self.tempNodes.length;
+ var epsilon = 0.00000000001;
+ var myD1 = 0.0,
+ myD2 = 0.0;
+ var A = 0.0,
+ B = 0.0,
+ C = 0.0;
+ var delta_x, delta_y;
+ var old_x, old_y, new_x, new_y;
+ var m = 0;
+ var max_delta = -1;
+ for (var i = 0; i < nodeCount; i++) {
+ var delta =
+ _self.VECTOR_D1[i] * _self.VECTOR_D1[i] +
+ _self.VECTOR_D2[i] * _self.VECTOR_D2[i];
+ if (delta > max_delta) {
+ m = i;
+ max_delta = delta;
+ }
+ }
+ if (max_delta < epsilon) {
+ return;
+ }
+ var nodeM = _self.tempNodes[m];
+ old_x = nodeM.x;
+ old_y = nodeM.y;
+ for (var i = 0; i < nodeCount; i++) {
+ if (i == m) {
+ continue;
+ }
+ var nodeI = _self.tempNodes[i];
+ var dx = old_x - nodeI.x;
+ var dy = old_y - nodeI.y;
+ var dist = Math.sqrt(dx * dx + dy * dy);
+ var den = dist * (dx * dx + dy * dy);
+ A += _self.kij[m][i] * (1.0 - (_self.lij[m][i] * dy * dy) / den);
+ B += _self.kij[m][i] * ((_self.lij[m][i] * dx * dy) / den);
+ C += _self.kij[m][i] * (1.0 - (_self.lij[m][i] * dx * dx) / den);
+ }
+ myD1 = _self.VECTOR_D1[m];
+ myD2 = _self.VECTOR_D2[m];
+ delta_y = (B * myD1 - myD2 * A) / (C * A - B * B);
+ delta_x = -(myD1 + B * delta_y) / A;
+ new_x = old_x + delta_x;
+ new_y = old_y + delta_y;
+ _self.VECTOR_D1[m] = _self.VECTOR_D2[m] = 0.0;
+ for (var i = 0; i < nodeCount; i++) {
+ if (i == m) {
+ continue;
+ }
+ var nodeI = _self.tempNodes[i];
+ var old_dx = old_x - nodeI.x;
+ var old_dy = old_y - nodeI.y;
+ var old_mi_dist = Math.sqrt(old_dx * old_dx + old_dy * old_dy);
+ var new_dx = new_x - nodeI.x;
+ var new_dy = new_y - nodeI.y;
+ var new_mi_dist = Math.sqrt(new_dx * new_dx + new_dy * new_dy);
+ _self.VECTOR_D1[i] -=
+ _self.kij[m][i] * (-old_dx + (_self.lij[m][i] * old_dx) / old_mi_dist);
+ _self.VECTOR_D2[i] -=
+ _self.kij[m][i] * (-old_dy + (_self.lij[m][i] * old_dy) / old_mi_dist);
+ _self.VECTOR_D1[i] +=
+ _self.kij[m][i] * (-new_dx + (_self.lij[m][i] * new_dx) / new_mi_dist);
+ _self.VECTOR_D2[i] +=
+ _self.kij[m][i] * (-new_dy + (_self.lij[m][i] * new_dy) / new_mi_dist);
+ _self.VECTOR_D1[m] +=
+ _self.kij[m][i] * (new_dx - (_self.lij[m][i] * new_dx) / new_mi_dist);
+ _self.VECTOR_D2[m] +=
+ _self.kij[m][i] * (new_dy - (_self.lij[m][i] * new_dy) / new_mi_dist);
+ }
+ nodeM.x = new_x;
+ nodeM.y = new_y;
+ var index = _self.nodeIds.indexOf(nodeM.id);
+ var node = _self.nodes[index];
+ node.x = new_x * (_self.realSize / _self.tempSize);
+ node.y = new_y * (_self.realSize / _self.tempSize);
+ };
+ KKLayout.prototype.getMaxDij = function (nodeCount, dij) {
+ var max_dij = 0;
+ for (var i = 0; i < nodeCount; i++) {
+ for (var j = i + 1; j < nodeCount; j++) {
+ if (dij[i][j] == Infinity) {
+ continue;
+ }
+ if (dij[i][j] > max_dij) {
+ max_dij = dij[i][j];
+ }
+ }
+ }
+ for (var i = 0; i < nodeCount; i++) {
+ for (var j = 0; j < nodeCount; j++) {
+ if (dij[i][j] == Infinity) {
+ dij[i][j] = max_dij;
+ }
+ }
+ }
+ return max_dij;
+ };
+ KKLayout.prototype.getKijLij = function (L0, max_dij, dij, kij, lij) {
+ var L = L0 / max_dij;
+ var nodeCount = this.tempNodes.length;
+ for (var i = 0; i < nodeCount; i++) {
+ kij[i] = [nodeCount];
+ lij[i] = [nodeCount];
+ for (var j = 0; j < nodeCount; j++) {
+ var tmp = dij[i][j] * dij[i][j];
+ if (i == j) {
+ continue;
+ }
+ kij[i][j] = (Math.pow(nodeCount, 2) * 1.0) / tmp;
+ lij[i][j] = L * dij[i][j];
+ }
+ }
+ };
+ KKLayout.prototype.shortPath = function (nodeCount) {
+ var _self = this;
+ var dij = [nodeCount];
+ for (var i = 0; i < nodeCount; i++) {
+ dij[i] = [nodeCount];
+ for (var j = 0; j < nodeCount; j++) {
+ if (i == j) {
+ dij[i][j] = 0;
+ continue;
+ }
+ dij[i][j] = Infinity;
+ }
+ }
+ _self.links.forEach(function (link) {
+ var i = _self.nodeIds.indexOf(link.source.id);
+ var j = _self.nodeIds.indexOf(link.target.id);
+ dij[i][j] = 1;
+ dij[j][i] = 1;
+ });
+ for (var k = 0; k < nodeCount; k++) {
+ for (var i = 0; i < nodeCount; i++) {
+ for (var j = i + 1; j < nodeCount; j++) {
+ var temp = dij[i][k] + dij[k][j];
+ if (temp < dij[i][j]) {
+ dij[i][j] = temp;
+ dij[j][i] = temp;
+ }
+ }
+ }
+ }
+ return dij;
+ };
+ KKLayout.prototype.setCanvasSize = function (nodeCount) {
+ var maxWidth = 8000;
+ var minWidth = 1500;
+ var widthRange = maxWidth - minWidth;
+ var shiftLog = 5;
+ var maxLog = Math.log(800 + shiftLog);
+ var minLog = Math.log(shiftLog);
+ var logRange = maxLog - minLog;
+ var canvasWidth = Math.round(
+ ((Math.log(Math.min(nodeCount, 8000) / 10 + shiftLog) - minLog) *
+ widthRange) /
+ logRange +
+ minWidth,
+ );
+ return canvasWidth;
+ };
+ var LayeredLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.layerDistance = 80;
+ this.ajustSize = true;
+ this.boolTransition = true;
+ this.intSteps = 50;
+ this.inited = false;
+ };
+ LayeredLayout.prototype.getConfig = function () {
+ return [{ label: "层间距", layerDistance: 80 }];
+ };
+ LayeredLayout.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.layerDistance = Number(layoutConfig["layerDistance"]) || 100;
+ this.initAlgo();
+ }
+ };
+ LayeredLayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ LayeredLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ LayeredLayout.prototype.initAlgo = function () {
+ var _self = this;
+ var nodes = _self.nodes;
+ var nodeCount = nodes.length;
+ var innerCircleRaduis = 0,
+ nextLayerRoundLong = 0,
+ currentRoundLong = 0;
+ var maxTheta = 0,
+ theta = 0;
+ this.inited = true;
+ nodes = nodes.sort(function (n1, n2) {
+ var x = (n1.inLinks || []).length + (n1.outLinks || []).length;
+ var y = (n2.inLinks || []).length + (n2.outLinks || []).length;
+ if (x < y) {
+ return -1;
+ } else if (x > y) {
+ return 1;
+ } else {
+ return 0;
+ }
+ });
+ var startValue = _self.getValue(nodes[0]);
+ var startX = nodes[0].x;
+ var startY = nodes[0].y;
+ var currentValue = startValue;
+ var isFirstlayer = true;
+ var shiftFirstlayer = 0;
+ var currentOrbit = [];
+ nodes.forEach(function (n) {
+ if (_self.getValue(n) != currentValue) {
+ if (isFirstlayer && currentOrbit.length > 1) {
+ shiftFirstlayer = 1;
+ }
+ isFirstlayer = false;
+ _self.renderOrbit(
+ currentOrbit,
+ startX,
+ startY,
+ shiftFirstlayer + (currentValue - startValue),
+ );
+ currentOrbit = [];
+ currentValue = _self.getValue(n);
+ }
+ currentOrbit.push(n);
+ });
+ if (currentOrbit.length > 0) {
+ _self.renderOrbit(
+ currentOrbit,
+ startX,
+ startY,
+ shiftFirstlayer + (currentValue - startValue),
+ );
+ }
+ };
+ LayeredLayout.prototype.getValue = function (node) {
+ return (node.inLinks || []).length + (node.outLinks || []).length;
+ };
+ LayeredLayout.prototype.goAlgo = function () {
+ var _self = this;
+ var position = null;
+ var nodes = _self.nodes;
+ var length = nodes.length;
+ for (var i = 0; i < length; i++) {
+ var n = nodes[i];
+ position = n.layoutData;
+ if (position == null) {
+ continue;
+ }
+ if (_self.boolTransition) {
+ var currentDistance = Math.abs(n.x - position.finishx);
+ var nextDistance = Math.abs(
+ n.x + position.xdistance - position.finishx,
+ );
+ if (nextDistance < currentDistance) {
+ n.x += position.xdistance;
+ } else {
+ n.x = position.finishx;
+ }
+ currentDistance = Math.abs(n.y - position.finishy);
+ nextDistance = Math.abs(n.y + position.ydistance - position.finishy);
+ if (nextDistance < currentDistance) {
+ n.y += position.ydistance;
+ } else {
+ n.y = position.finishy;
+ }
+ if (n.x == position.finishx && n.y == position.finishy) {
+ n.layoutData = null;
+ }
+ } else {
+ n.x = position.finishx;
+ n.y = position.finishy;
+ n.layoutData = null;
+ }
+ }
+ };
+ LayeredLayout.prototype.renderOrbit = function (
+ currentOrbit,
+ startX,
+ startY,
+ radius,
+ ) {
+ var _self = this;
+ if (_self.ajustSize) {
+ let length = 0;
+ currentOrbit.forEach(function (n) {
+ length += n.radius;
+ });
+ var currentAngle = 0;
+ var shift = 360 / length;
+ currentOrbit.forEach(function (o, i) {
+ currentAngle += (shift * o.radius) / 2;
+ var noise = 0;
+ if (i % 3 == 1) {
+ noise = o.radius * -1;
+ }
+ if (i % 3 == 2) {
+ noise = o.radius;
+ }
+ var x =
+ startX +
+ (_self.layerDistance * radius + noise) *
+ Math.cos(currentAngle * (Math.PI / 180));
+ var y =
+ startY +
+ (_self.layerDistance * radius + noise) *
+ Math.sin(currentAngle * (Math.PI / 180));
+ currentAngle += (shift * o.radius) / 2;
+ var posData = _self.newLayoutData();
+ posData.finishx = x;
+ posData.finishy = y;
+ posData.xdistance = (1.0 / _self.intSteps) * (x - o.x);
+ posData.ydistance = (1.0 / _self.intSteps) * (y - o.y);
+ o.layoutData = posData;
+ });
+ } else {
+ var currentAngle = 0;
+ var shift = 360 / currentOrbit.length;
+ currentOrbit.forEach(function (o) {
+ var x =
+ startX +
+ _self.layerDistance *
+ radius *
+ Math.cos(currentAngle * (Math.PI / 180));
+ var y =
+ startY +
+ _self.layerDistance *
+ radius *
+ Math.sin(currentAngle * (Math.PI / 180));
+ var posData = _self.newLayoutData();
+ posData.finishx = x;
+ posData.finishy = y;
+ posData.xdistance = (1.0 / _self.intSteps) * (x - o.x);
+ posData.ydistance = (1.0 / _self.intSteps) * (y - o.y);
+ o.layoutData = posData;
+ currentAngle += shift;
+ });
+ }
+ };
+ var ConcentricLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.defaults = {
+ startAngle: Math.PI,
+ clockwise: true,
+ equidistant: false,
+ avoidOverlap: true,
+ minNodeSpacing: 10,
+ maxNodeSize: 50,
+ levelWidth: 1,
+ };
+ this.boolTransition = true;
+ this.intSteps = 50;
+ this.inited = false;
+ };
+ ConcentricLayout.prototype.getConfig = function () {
+ return [
+ { label: "节点大小", maxNodeSize: 50 },
+ { label: "分层系数", levelWidth: 1 },
+ ];
+ };
+ ConcentricLayout.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.defaults.maxNodeSize = Number(layoutConfig["maxNodeSize"]) || 50;
+ this.defaults.levelWidth = Number(layoutConfig["levelWidth"]) || 1;
+ }
+ this.initAlgo();
+ };
+ ConcentricLayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ ConcentricLayout.prototype.initAlgo = function () {
+ var self = this;
+ let options = self.defaults;
+ let nodes = self.nodes;
+ var bb = {
+ x1: 0,
+ y1: 0,
+ w: options.maxNodeSize * 5,
+ h: options.maxNodeSize * 5,
+ };
+ let center = { x: bb.x1 + bb.w / 2, y: bb.y1 + bb.h / 2 };
+ let nodeValues = [];
+ for (let i = 0; i < nodes.length; i++) {
+ let node = nodes[i];
+ let value;
+ value = (node.inLinks || []).length + (node.outLinks || []).length;
+ nodeValues.push({ value: value, node: node });
+ }
+ nodeValues.sort(function (a, b) {
+ return b.value - a.value;
+ });
+ let levelWidth = options.levelWidth;
+ let levels = [[]];
+ let currentLevel = levels[0];
+ for (let i = 0; i < nodeValues.length; i++) {
+ let val = nodeValues[i];
+ if (currentLevel.length > 0) {
+ let diff = Math.abs(currentLevel[0].value - val.value);
+ if (diff >= levelWidth) {
+ currentLevel = [];
+ levels.push(currentLevel);
+ }
+ }
+ currentLevel.push(val);
+ }
+ let minDist = options.maxNodeSize + options.minNodeSpacing;
+ if (options.avoidOverlap) {
+ let firstLvlHasMulti = levels.length > 0 && levels[0].length > 1;
+ let maxR = Math.min(bb.w, bb.h) / 2 - minDist;
+ let rStep = maxR / (levels.length + firstLvlHasMulti ? 1 : 0);
+ minDist = Math.min(minDist, rStep);
+ }
+ let r = 0;
+ for (let i = 0; i < levels.length; i++) {
+ let level = levels[i];
+ let sweep = 2 * Math.PI - (2 * Math.PI) / level.length;
+ let dTheta = (level.dTheta = sweep / Math.max(1, level.length - 1));
+ if (level.length > 1 && options.avoidOverlap) {
+ let dcos = Math.cos(dTheta) - Math.cos(0);
+ let dsin = Math.sin(dTheta) - Math.sin(0);
+ let rMin = Math.sqrt((minDist * minDist) / (dcos * dcos + dsin * dsin));
+ r = Math.max(rMin, r);
+ }
+ level.r = r;
+ r += minDist;
+ }
+ if (options.equidistant) {
+ let rDeltaMax = 0;
+ let r = 0;
+ for (let i = 0; i < levels.length; i++) {
+ let level = levels[i];
+ let rDelta = level.r - r;
+ rDeltaMax = Math.max(rDeltaMax, rDelta);
+ }
+ r = 0;
+ for (let i = 0; i < levels.length; i++) {
+ let level = levels[i];
+ if (i === 0) {
+ r = level.r;
+ }
+ level.r = r;
+ r += rDeltaMax;
+ }
+ }
+ for (let i = 0; i < levels.length; i++) {
+ let level = levels[i];
+ let dTheta = level.dTheta;
+ let r = level.r;
+ for (let j = 0; j < level.length; j++) {
+ let val = level[j];
+ let theta = options.startAngle + (self.clockwise ? 1 : -1) * dTheta * j;
+ var x = center.x + r * Math.cos(theta);
+ var y = center.y + r * Math.sin(theta);
+ var posData = self.newLayoutData();
+ posData.finishx = x;
+ posData.finishy = y;
+ posData.xdistance = (1.0 / self.intSteps) * (x - val.node.x);
+ posData.ydistance = (1.0 / self.intSteps) * (y - val.node.y);
+ val.node.layoutData = posData;
+ }
+ }
+ this.inited = true;
+ };
+ ConcentricLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ ConcentricLayout.prototype.goAlgo = function () {
+ var _self = this;
+ var position = null;
+ var nodes = _self.nodes;
+ var length = nodes.length;
+ for (var i = 0; i < length; i++) {
+ var n = nodes[i];
+ position = n.layoutData;
+ if (position == null) {
+ continue;
+ }
+ if (_self.boolTransition) {
+ var currentDistance = Math.abs(n.x - position.finishx);
+ var nextDistance = Math.abs(
+ n.x + position.xdistance - position.finishx,
+ );
+ if (nextDistance < currentDistance) {
+ n.x += position.xdistance;
+ } else {
+ n.x = position.finishx;
+ }
+ currentDistance = Math.abs(n.y - position.finishy);
+ nextDistance = Math.abs(n.y + position.ydistance - position.finishy);
+ if (nextDistance < currentDistance) {
+ n.y += position.ydistance;
+ } else {
+ n.y = position.finishy;
+ }
+ if (n.x == position.finishx && n.y == position.finishy) {
+ n.layoutData = null;
+ }
+ } else {
+ n.x = position.finishx;
+ n.y = position.finishy;
+ n.layoutData = null;
+ }
+ }
+ };
+ var RotateLayout = function (nodes, links, angle) {
+ this.nodes = nodes;
+ this.links = links;
+ this.angle = angle || 10;
+ this.direction = "sn";
+ this.boolTransition = true;
+ this.intSteps = 30;
+ this.inited = false;
+ };
+ RotateLayout.prototype.getConfig = function () {
+ return [
+ { label: "旋转角度", angle: 10 },
+ {
+ label: "旋转方向",
+ direction: [
+ { label: "顺时针", value: "sn" },
+ { label: "逆时针", value: "ns" },
+ ],
+ },
+ ];
+ };
+ RotateLayout.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.angle = Number(layoutConfig["angle"]) || 10;
+ this.direction = layoutConfig["direction"] || "sn";
+ }
+ if (this.direction == "ns") {
+ this.angle = Math.abs(this.angle);
+ } else {
+ this.angle = -Math.abs(this.angle);
+ }
+ this.initAlgo();
+ };
+ RotateLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ RotateLayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ RotateLayout.prototype.initAlgo = function () {
+ var self = this;
+ var sin = Math.sin((-self.angle * Math.PI) / 180);
+ var cos = Math.cos((-self.angle * Math.PI) / 180);
+ var px = 0;
+ var py = 0;
+ self.nodes.forEach(function (n) {
+ var dx = n.x - px;
+ var dy = n.y - py;
+ var tempX = px + dx * cos - dy * sin;
+ var tempY = py + dy * cos + dx * sin;
+ var posData = self.newLayoutData();
+ posData.finishx = tempX;
+ posData.finishy = tempY;
+ posData.xdistance = (1.0 / self.intSteps) * (tempX - n.x);
+ posData.ydistance = (1.0 / self.intSteps) * (tempY - n.y);
+ n.layoutData = posData;
+ });
+ this.inited = true;
+ };
+ RotateLayout.prototype.goAlgo = function () {
+ var _self = this;
+ var position = null;
+ var nodes = _self.nodes;
+ var length = nodes.length;
+ for (var i = 0; i < length; i++) {
+ var n = nodes[i];
+ position = n.layoutData;
+ if (position == null) {
+ continue;
+ }
+ if (_self.boolTransition) {
+ var currentDistance = Math.abs(n.x - position.finishx);
+ var nextDistance = Math.abs(
+ n.x + position.xdistance - position.finishx,
+ );
+ if (nextDistance < currentDistance) {
+ n.x += position.xdistance;
+ } else {
+ n.x = position.finishx;
+ }
+ currentDistance = Math.abs(n.y - position.finishy);
+ nextDistance = Math.abs(n.y + position.ydistance - position.finishy);
+ if (nextDistance < currentDistance) {
+ n.y += position.ydistance;
+ } else {
+ n.y = position.finishy;
+ }
+ if (n.x == position.finishx && n.y == position.finishy) {
+ n.layoutData = null;
+ }
+ } else {
+ n.x = position.finishx;
+ n.y = position.finishy;
+ n.layoutData = null;
+ }
+ }
+ };
+ var ScaleLayout = function (nodes, links, scale) {
+ this.nodes = nodes;
+ this.links = links;
+ this.scale = scale || 1;
+ this.boolTransition = true;
+ this.intSteps = 30;
+ this.inited = false;
+ };
+ ScaleLayout.prototype.getConfig = function () {
+ return [{ label: "缩放比例", scale: 1.1 }];
+ };
+ ScaleLayout.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.scale = Number(layoutConfig["scale"]) || 1.1;
+ }
+ this.initAlgo();
+ };
+ ScaleLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ ScaleLayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ ScaleLayout.prototype.initAlgo = function () {
+ var self = this;
+ var nodeCount = self.nodes.length;
+ var xMean = 0,
+ yMean = 0;
+ this.inited = true;
+ self.nodes.forEach(function (n) {
+ xMean += n.x;
+ yMean += n.y;
+ });
+ xMean /= nodeCount;
+ yMean /= nodeCount;
+ self.nodes.forEach(function (n) {
+ var dx = (n.x - xMean) * self.scale;
+ var dy = (n.y - yMean) * self.scale;
+ var tempX = xMean + dx;
+ var tempY = yMean + dy;
+ var posData = self.newLayoutData();
+ posData.finishx = tempX;
+ posData.finishy = tempY;
+ posData.xdistance = (1.0 / self.intSteps) * (tempX - n.x);
+ posData.ydistance = (1.0 / self.intSteps) * (tempY - n.y);
+ n.layoutData = posData;
+ });
+ };
+ ScaleLayout.prototype.goAlgo = function () {
+ var _self = this;
+ var position = null;
+ var nodes = _self.nodes;
+ var length = nodes.length;
+ for (var i = 0; i < length; i++) {
+ var n = nodes[i];
+ position = n.layoutData;
+ if (position == null) {
+ continue;
+ }
+ if (_self.boolTransition) {
+ var currentDistance = Math.abs(n.x - position.finishx);
+ var nextDistance = Math.abs(
+ n.x + position.xdistance - position.finishx,
+ );
+ if (nextDistance < currentDistance) {
+ n.x += position.xdistance;
+ } else {
+ n.x = position.finishx;
+ }
+ currentDistance = Math.abs(n.y - position.finishy);
+ nextDistance = Math.abs(n.y + position.ydistance - position.finishy);
+ if (nextDistance < currentDistance) {
+ n.y += position.ydistance;
+ } else {
+ n.y = position.finishy;
+ }
+ if (n.x == position.finishx && n.y == position.finishy) {
+ n.layoutData = null;
+ }
+ } else {
+ n.x = position.finishx;
+ n.y = position.finishy;
+ n.layoutData = null;
+ }
+ }
+ };
+ var SpringLayout2 = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.stretch = 0.5;
+ this.repulsion_range_sq = 2000;
+ this.force_multiplier = 0.02;
+ this.inited = false;
+ };
+ SpringLayout2.prototype.newLayoutData = function () {
+ var layoutData = {
+ edgedx: 0.0,
+ edgedy: 0.0,
+ repulsiondx: 0.0,
+ repulsiondy: 0.0,
+ dx: 0.0,
+ dy: 0.0,
+ };
+ return layoutData;
+ };
+ SpringLayout2.prototype.getConfig = function () {
+ return [
+ { label: "区域大小", repulsion: 1000000 },
+ { label: "边长度", stretch: 0.015 },
+ { label: "收敛系数", force: 10.0 },
+ ];
+ };
+ SpringLayout2.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.stretch = Number(layoutConfig["stretch"]) || 0.015;
+ this.repulsion_range_sq = Number(layoutConfig["repulsion"]) || 1000000;
+ this.force_multiplier = Number(layoutConfig["force"]) || 10;
+ }
+ this.initAlgo();
+ };
+ SpringLayout2.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ SpringLayout2.prototype.initAlgo = function () {
+ var _self = this;
+ _self.nodes.forEach(function (n) {
+ n.layoutData = _self.newLayoutData();
+ });
+ this.inited = true;
+ };
+ SpringLayout2.prototype.goAlgo = function () {
+ var _self = this;
+ _self.nodes.forEach(function (n) {
+ var svd = n.layoutData;
+ svd.dx /= 4;
+ svd.dy /= 4;
+ svd.edgedx = svd.edgedy = 0;
+ svd.repulsiondx = svd.repulsiondy = 0;
+ });
+ _self.relaxEdges();
+ _self.calculateRepulsion();
+ _self.moveNodes();
+ };
+ SpringLayout2.prototype.relaxEdges = function () {
+ var _self = this;
+ _self.links.forEach(function (link) {
+ var node1 = link.source;
+ var node2 = link.target;
+ var vx = node1.x - node2.x;
+ var vy = node1.y - node2.y;
+ var len = Math.sqrt(vx * vx + vy * vy);
+ len = len == 0 ? 0.0001 : len;
+ var f = (_self.force_multiplier * (1 - len)) / len;
+ f = f * Math.pow(_self.stretch, 2);
+ var dx = f * vx;
+ var dy = f * vy;
+ var v1D = node1.layoutData;
+ var v2D = node2.layoutData;
+ v1D.edgedx += dx;
+ v1D.edgedy += dy;
+ v2D.edgedx += -dx;
+ v2D.edgedy += -dy;
+ });
+ };
+ SpringLayout2.prototype.calculateRepulsion = function () {
+ var _self = this;
+ _self.nodes.forEach(function (node) {
+ var dx = 0,
+ dy = 0;
+ _self.nodes.forEach(function (n) {
+ if (node.id != n.id) {
+ var vx = node.x - n.x;
+ var vy = node.y - n.y;
+ var distanceSq = vx * vx + vy * vy;
+ if (distanceSq == 0) {
+ dx += Math.random();
+ dy += Math.random();
+ } else if (distanceSq < _self.repulsion_range_sq) {
+ var factor = 1;
+ dx += (factor * vx) / distanceSq;
+ dy += (factor * vy) / distanceSq;
+ }
+ }
+ });
+ var dlen = dx * dx + dy * dy;
+ if (dlen > 0) {
+ dlen = Math.sqrt(dlen) / 2;
+ var layoutData = node.layoutData;
+ layoutData.repulsiondx += dx / dlen;
+ layoutData.repulsiondy += dy / dlen;
+ }
+ });
+ };
+ SpringLayout2.prototype.moveNodes = function () {
+ var _self = this;
+ _self.nodes.forEach(function (node) {
+ var vd = node.layoutData;
+ vd.dx += vd.repulsiondx + vd.edgedx;
+ vd.dy += vd.repulsiondy + vd.edgedy;
+ node.x += Math.max(-5, Math.min(5, vd.dx));
+ node.y += Math.max(-5, Math.min(5, vd.dy));
+ });
+ };
+ var SphereLayout = function (nodes, links, radius) {
+ this.nodes = nodes;
+ this.links = links;
+ this.radius = radius || 800;
+ this.boolTransition = true;
+ this.intSteps = 30;
+ this.inited = false;
+ };
+ SphereLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ SphereLayout.prototype.getConfig = function () {
+ return [{ label: "半径", radius: 500 }];
+ };
+ SphereLayout.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.radius = Number(layoutConfig["radius"]) || 500;
+ }
+ this.initAlgo();
+ };
+ SphereLayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ SphereLayout.prototype.initAlgo = function () {
+ var self = this;
+ var nodeCount = self.nodes.length;
+ this.inited = true;
+ var area = 0;
+ self.nodes.forEach(function (n, i) {
+ var phi = Math.acos(-1 + (2 * i) / nodeCount);
+ var theta = Math.sqrt(nodeCount * Math.PI) * phi;
+ var sinPhiRadius = Math.sin(phi) * self.radius;
+ var tempX = sinPhiRadius * Math.sin(theta);
+ var tempY = Math.cos(phi) * self.radius;
+ var posData = self.newLayoutData();
+ posData.finishx = tempX;
+ posData.finishy = tempY;
+ posData.xdistance = (1.0 / self.intSteps) * (tempX - n.x);
+ posData.ydistance = (1.0 / self.intSteps) * (tempY - n.y);
+ n.layoutData = posData;
+ });
+ };
+ SphereLayout.prototype.goAlgo = function () {
+ var _self = this;
+ var position = null;
+ var nodes = _self.nodes;
+ var length = nodes.length;
+ for (var i = 0; i < length; i++) {
+ var n = nodes[i];
+ position = n.layoutData;
+ if (position == null) {
+ continue;
+ }
+ if (_self.boolTransition) {
+ var currentDistance = Math.abs(n.x - position.finishx);
+ var nextDistance = Math.abs(
+ n.x + position.xdistance - position.finishx,
+ );
+ if (nextDistance < currentDistance) {
+ n.x += position.xdistance;
+ } else {
+ n.x = position.finishx;
+ }
+ currentDistance = Math.abs(n.y - position.finishy);
+ nextDistance = Math.abs(n.y + position.ydistance - position.finishy);
+ if (nextDistance < currentDistance) {
+ n.y += position.ydistance;
+ } else {
+ n.y = position.finishy;
+ }
+ if (n.x == position.finishx && n.y == position.finishy) {
+ n.layoutData = null;
+ }
+ } else {
+ n.x = position.finishx;
+ n.y = position.finishy;
+ n.layoutData = null;
+ }
+ }
+ };
+ var TreeLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.nodeIds = [];
+ this.nodeNeighbers = [];
+ this.distX = 80;
+ this.distY = 80;
+ this.currentX = 0;
+ this.currentY = 0;
+ this.direction = "UD";
+ this.boolTransition = true;
+ this.intSteps = 50;
+ this.hasCycle = false;
+ this.inited = false;
+ };
+ TreeLayout.prototype.getConfig = function () {
+ return [
+ { label: "点间距", distX: 80 },
+ { label: "层间距", distY: 120 },
+ {
+ label: "排列方向",
+ direction: [
+ { label: "上下", value: "UD" },
+ { label: "下上", value: "DU" },
+ { label: "左右", value: "LR" },
+ { label: "右左", value: "RL" },
+ ],
+ },
+ ];
+ };
+ TreeLayout.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.distX = Number(layoutConfig["distX"]) || 100;
+ this.distY = Number(layoutConfig["distY"]) || 120;
+ this.direction = layoutConfig["direction"] || "UD";
+ }
+ this.nodeIds = [];
+ this.nodeNeighbers = [];
+ this.initAlgo();
+ };
+ TreeLayout.prototype.initAlgo = function () {
+ var _self = this;
+ _self.nodes.forEach(function (node) {
+ _self.checkHasCycle(node, []);
+ _self.nodeIds.push(node.id);
+ var neighbers = _self.initNodeNeighbers(node);
+ _self.nodeNeighbers.push(neighbers);
+ });
+ _self.buildTree();
+ this.inited = true;
+ };
+ TreeLayout.prototype.initNodeNeighbers = function (node) {
+ var _self = this;
+ var nodeNeighbers = [];
+ var outLinks = node.outLinks || [];
+ outLinks.forEach(function (link) {
+ var target = link.target;
+ var source = link.source;
+ if (source.id != target.id && source.visible && target.visible) {
+ var index = _self.nodeIds.indexOf(target.id);
+ var childNodes = _self.nodeNeighbers[index] || [];
+ var childNodeIds = [];
+ childNodes.forEach(function (n) {
+ childNodeIds.push(n.id);
+ });
+ if (childNodeIds.indexOf(node.id) == -1) {
+ nodeNeighbers.push(target);
+ }
+ }
+ });
+ return nodeNeighbers;
+ };
+ TreeLayout.prototype.runLayout = function () {
+ if (!this.hasCycle && this.inited) {
+ this.goAlgo();
+ }
+ };
+ TreeLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ TreeLayout.prototype.buildTree = function () {
+ var _self = this;
+ var roots = _self.getRoots();
+ if (roots.length > 0) {
+ _self.calculateRootsX(roots);
+ roots.forEach(function (node) {
+ _self.calculateNodeX(node);
+ _self.currentX += node.sizeT / 2 + _self.distX;
+ _self.buildNodeTree(node, _self.currentX);
+ });
+ }
+ };
+ TreeLayout.prototype.getRoots = function () {
+ var _self = this;
+ var roots = [];
+ _self.nodes.forEach(function (node) {
+ if ((node.inLinks || []).length == 0) {
+ roots.push(node);
+ }
+ });
+ return roots;
+ };
+ TreeLayout.prototype.calculateRootsX = function (roots) {
+ var _self = this;
+ var size = 0;
+ roots.forEach(function (node) {
+ var childNodes = _self.getSuccessors(node);
+ var childrenNum = childNodes.length;
+ if (childrenNum != 0) {
+ childNodes.forEach(function (node) {
+ size += _self.calculateNodeX(node) + _self.distX;
+ });
+ }
+ size = Math.max(0, size - _self.distX);
+ node.sizeT = size;
+ });
+ return size;
+ };
+ TreeLayout.prototype.calculateNodeX = function (node) {
+ var _self = this;
+ var size = 0;
+ var childNodes = _self.getSuccessors(node);
+ var childrenNum = childNodes.length;
+ if (childrenNum != 0) {
+ childNodes.forEach(function (node) {
+ size += _self.calculateNodeX(node) + _self.distX;
+ });
+ }
+ size = Math.max(0, size - _self.distX);
+ node.sizeT = size;
+ return size;
+ };
+ TreeLayout.prototype.buildNodeTree = function (node, x) {
+ var _self = this;
+ _self.currentY += _self.distY;
+ _self.currentX = x;
+ _self.setCurrentPositionFor(node);
+ var sizeXofCurrent = node.sizeT;
+ var lastX = x - sizeXofCurrent / 2;
+ var sizeXofChild;
+ var startXofChild;
+ var childNodes = _self.getSuccessors(node);
+ childNodes.forEach(function (n) {
+ sizeXofChild = n.sizeT;
+ startXofChild = lastX + sizeXofChild / 2;
+ _self.buildNodeTree(n, startXofChild);
+ lastX = lastX + sizeXofChild + _self.distX;
+ });
+ _self.currentY -= _self.distY;
+ };
+ TreeLayout.prototype.setCurrentPositionFor = function (node) {
+ var _self = this;
+ var x = _self.currentX;
+ var y = _self.currentY;
+ var tempx = x;
+ if (_self.direction == "DU") {
+ y = -y;
+ } else if (_self.direction == "LR") {
+ x = y;
+ y = tempx;
+ } else if (_self.direction == "RL") {
+ x = -y;
+ y = tempx;
+ }
+ var posData = _self.newLayoutData();
+ posData.finishx = x;
+ posData.finishy = y;
+ posData.xdistance = (1.0 / _self.intSteps) * (x - node.x);
+ posData.ydistance = (1.0 / _self.intSteps) * (y - node.y);
+ node.layoutData = posData;
+ };
+ TreeLayout.prototype.getSuccessors = function (node) {
+ var _self = this;
+ var index = _self.nodeIds.indexOf(node.id);
+ var childNodes = _self.nodeNeighbers[index] || [];
+ return childNodes;
+ };
+ TreeLayout.prototype.goAlgo = function () {
+ var _self = this;
+ var position = null;
+ var nodes = _self.nodes;
+ var length = nodes.length;
+ for (var i = 0; i < length; i++) {
+ var n = nodes[i];
+ position = n.layoutData;
+ if (position == null) {
+ continue;
+ }
+ if (_self.boolTransition) {
+ var currentDistance = Math.abs(n.x - position.finishx);
+ var nextDistance = Math.abs(
+ n.x + position.xdistance - position.finishx,
+ );
+ if (nextDistance < currentDistance) {
+ n.x += position.xdistance;
+ } else {
+ n.x = position.finishx;
+ }
+ currentDistance = Math.abs(n.y - position.finishy);
+ nextDistance = Math.abs(n.y + position.ydistance - position.finishy);
+ if (nextDistance < currentDistance) {
+ n.y += position.ydistance;
+ } else {
+ n.y = position.finishy;
+ }
+ if (n.x == position.finishx && n.y == position.finishy) {
+ n.layoutData = null;
+ }
+ } else {
+ n.x = position.finishx;
+ n.y = position.finishy;
+ n.layoutData = null;
+ }
+ }
+ };
+ TreeLayout.prototype.checkHasCycle = function (node, pathNodes) {
+ var _self = this;
+ (node.outLinks || []).forEach(function (_link) {
+ var target = _link.target;
+ if (node.id == target.id || pathNodes.indexOf(target.id) != -1) {
+ _self.hasCycle = true;
+ return;
+ }
+ pathNodes.push(target.id);
+ _self.checkHasCycle(target, pathNodes);
+ });
+ };
+ var BalloonLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.nodeIds = [];
+ this.nodeNeighbers = [];
+ this.distX = 50;
+ this.distY = 50;
+ this.currentX = 0;
+ this.currentY = 0;
+ this.radius = 1000;
+ this.boolTransition = true;
+ this.intSteps = 50;
+ this.hasCycle = false;
+ this.inited = false;
+ };
+ BalloonLayout.prototype.getConfig = function () {
+ return [{ label: "区域大小", radius: 1000 }];
+ };
+ BalloonLayout.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.radius = Number(layoutConfig["radius"]) || 1000;
+ }
+ this.initAlgo();
+ };
+ BalloonLayout.prototype.runLayout = function () {
+ if (!this.hasCycle && this.inited) {
+ this.goAlgo();
+ }
+ };
+ BalloonLayout.prototype.initAlgo = function () {
+ var _self = this;
+ this.inited = true;
+ _self.nodeIds = [];
+ _self.nodeNeighbers = [];
+ _self.nodes.forEach(function (node) {
+ _self.nodeIds.push(node.id);
+ var neighbers = _self.initNodeNeighbers(node);
+ _self.nodeNeighbers.push(neighbers);
+ _self.checkHasCycle(node, []);
+ });
+ _self.buildTree();
+ _self.setRootPolars();
+ };
+ BalloonLayout.prototype.initNodeNeighbers = function (node) {
+ var _self = this;
+ var nodeNeighbers = [];
+ var outLinks = node.outLinks || [];
+ outLinks.forEach(function (link) {
+ var target = link.target;
+ var source = link.source;
+ if (source.id != target.id && source.visible && target.visible) {
+ var index = _self.nodeIds.indexOf(target.id);
+ var childNodes = _self.nodeNeighbers[index] || [];
+ var childNodeIds = [];
+ childNodes.forEach(function (n) {
+ childNodeIds.push(n.id);
+ });
+ if (childNodeIds.indexOf(node.id) == -1) {
+ nodeNeighbers.push(target);
+ }
+ }
+ });
+ return nodeNeighbers;
+ };
+ BalloonLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ BalloonLayout.prototype.setRootPolars = function () {
+ var _self = this;
+ var roots = _self.getRoots();
+ var center = _self.getCenter();
+ _self.setPolars(roots, center, _self.radius);
+ };
+ BalloonLayout.prototype.setRootPolar = function (root) {
+ root.x = 10;
+ root.y = 10;
+ };
+ BalloonLayout.prototype.setPolars = function (
+ kids,
+ parentLocation,
+ parentRadius,
+ ) {
+ var _self = this;
+ var childCount = kids.length;
+ if (childCount == 0) {
+ return;
+ }
+ var angle = Math.max(0, (Math.PI / 2) * (1 - 2.0 / childCount));
+ var childRadius = (parentRadius * Math.cos(angle)) / (1 + Math.cos(angle));
+ var radius = parentRadius - childRadius;
+ var rand = Math.random();
+ for (var i = 0; i < childCount; i++) {
+ var node = kids[i];
+ var theta = (i * 2 * Math.PI) / childCount + rand;
+ var x = radius * Math.cos(theta);
+ var y = radius * Math.sin(theta);
+ x = x + parentLocation.x;
+ y = y + parentLocation.y;
+ var posData = _self.newLayoutData();
+ posData.finishx = x;
+ posData.finishy = y;
+ posData.xdistance = (1.0 / _self.intSteps) * (x - node.x);
+ posData.ydistance = (1.0 / _self.intSteps) * (y - node.y);
+ node.layoutData = posData;
+ var p = { x: x, y: y };
+ var childNodes = _self.getSuccessors(node);
+ _self.setPolars(childNodes, p, childRadius);
+ }
+ };
+ BalloonLayout.prototype.getCenter = function (node) {
+ var _self = this;
+ var parent = _self.getParent(node);
+ if (parent == null) {
+ return _self.getCenter();
+ }
+ return { x: parent.x, y: parent.y };
+ };
+ BalloonLayout.prototype.getCenter = function () {
+ var _self = this;
+ return { x: 0, y: 0 };
+ };
+ BalloonLayout.prototype.getParent = function (node) {
+ var inLinks = node.inLinks || [];
+ if (inLinks.length > 0) {
+ return inLinks[0].source;
+ }
+ return null;
+ };
+ BalloonLayout.prototype.buildTree = function () {
+ var _self = this;
+ var roots = _self.getRoots();
+ if (roots.length > 0) {
+ _self.calculateRootsX(roots);
+ roots.forEach(function (node) {
+ _self.calculateNodeX(node);
+ _self.currentX += node.sizeT / 2 + _self.distX;
+ _self.buildNodeTree(node, _self.currentX);
+ });
+ }
+ };
+ BalloonLayout.prototype.getRoots = function () {
+ var _self = this;
+ var roots = [];
+ _self.nodes.forEach(function (node) {
+ if ((node.inLinks || []).length == 0) {
+ roots.push(node);
+ }
+ });
+ return roots;
+ };
+ BalloonLayout.prototype.calculateRootsX = function (roots) {
+ var _self = this;
+ var size = 0;
+ roots.forEach(function (node) {
+ var childNodes = _self.getSuccessors(node);
+ var childrenNum = childNodes.length;
+ if (childrenNum != 0) {
+ childNodes.forEach(function (node) {
+ size += _self.calculateNodeX(node) + _self.distX;
+ });
+ }
+ size = Math.max(0, size - _self.distX);
+ node.sizeT = size;
+ });
+ return size;
+ };
+ BalloonLayout.prototype.calculateNodeX = function (node) {
+ var _self = this;
+ var size = 0;
+ var childNodes = _self.getSuccessors(node);
+ var childrenNum = childNodes.length;
+ if (childrenNum != 0) {
+ childNodes.forEach(function (node) {
+ size += _self.calculateNodeX(node) + _self.distX;
+ });
+ }
+ size = Math.max(0, size - _self.distX);
+ node.sizeT = size;
+ return size;
+ };
+ BalloonLayout.prototype.buildNodeTree = function (node, x) {
+ var _self = this;
+ _self.currentY += _self.distY;
+ _self.currentX = x;
+ _self.setCurrentPositionFor(node);
+ var sizeXofCurrent = node.sizeT;
+ var lastX = x - sizeXofCurrent / 2;
+ var sizeXofChild;
+ var startXofChild;
+ var childNodes = _self.getSuccessors(node);
+ childNodes.forEach(function (n) {
+ sizeXofChild = n.sizeT;
+ startXofChild = lastX + sizeXofChild / 2;
+ _self.buildNodeTree(n, startXofChild);
+ lastX = lastX + sizeXofChild + _self.distX;
+ });
+ _self.currentY -= _self.distY;
+ };
+ BalloonLayout.prototype.setCurrentPositionFor = function (node) {
+ var _self = this;
+ var x = _self.currentX;
+ var y = _self.currentY;
+ node.tempx = x;
+ node.tempy = y;
+ };
+ BalloonLayout.prototype.getSuccessors = function (node) {
+ var _self = this;
+ var index = _self.nodeIds.indexOf(node.id);
+ var childNodes = _self.nodeNeighbers[index] || [];
+ return childNodes;
+ };
+ BalloonLayout.prototype.goAlgo = function () {
+ var _self = this;
+ var position = null;
+ var nodes = _self.nodes;
+ var length = nodes.length;
+ for (var i = 0; i < length; i++) {
+ var n = nodes[i];
+ position = n.layoutData;
+ if (position == null) {
+ continue;
+ }
+ if (_self.boolTransition) {
+ var currentDistance = Math.abs(n.x - position.finishx);
+ var nextDistance = Math.abs(
+ n.x + position.xdistance - position.finishx,
+ );
+ if (nextDistance < currentDistance) {
+ n.x += position.xdistance;
+ } else {
+ n.x = position.finishx;
+ }
+ currentDistance = Math.abs(n.y - position.finishy);
+ nextDistance = Math.abs(n.y + position.ydistance - position.finishy);
+ if (nextDistance < currentDistance) {
+ n.y += position.ydistance;
+ } else {
+ n.y = position.finishy;
+ }
+ if (n.x == position.finishx && n.y == position.finishy) {
+ n.layoutData = null;
+ }
+ } else {
+ n.x = position.finishx;
+ n.y = position.finishy;
+ n.layoutData = null;
+ }
+ }
+ };
+ BalloonLayout.prototype.checkHasCycle = function (node, pathNodes) {
+ var _self = this;
+ (node.outLinks || []).forEach(function (_link) {
+ var target = _link.target;
+ if (node.id == target.id || pathNodes.indexOf(target.id) != -1) {
+ _self.hasCycle = true;
+ return;
+ }
+ pathNodes.push(target.id);
+ _self.checkHasCycle(target, pathNodes);
+ });
+ };
+ var RadiaTreeLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.nodeIds = [];
+ this.nodeNeighbers = [];
+ this.distX = 50;
+ this.distY = 50;
+ this.currentX = 0;
+ this.currentY = 0;
+ this.boolTransition = true;
+ this.intSteps = 50;
+ this.hasCycle = false;
+ this.inited = false;
+ };
+ RadiaTreeLayout.prototype.getConfig = function () {
+ return [
+ { label: "水平间距", distX: 50 },
+ { label: "垂直间距", distY: 50 },
+ ];
+ };
+ RadiaTreeLayout.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.distX = Number(layoutConfig["distX"]) || 50;
+ this.distY = Number(layoutConfig["distY"]) || 50;
+ }
+ this.initAlgo();
+ };
+ RadiaTreeLayout.prototype.runLayout = function () {
+ if (!this.hasCycle && this.inited) {
+ this.goAlgo();
+ }
+ };
+ RadiaTreeLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ RadiaTreeLayout.prototype.initAlgo = function () {
+ var _self = this;
+ this.inited = true;
+ _self.nodeIds = [];
+ _self.nodeNeighbers = [];
+ _self.nodes.forEach(function (node) {
+ _self.nodeIds.push(node.id);
+ var neighbers = _self.initNodeNeighbers(node);
+ _self.nodeNeighbers.push(neighbers);
+ _self.checkHasCycle(node, []);
+ });
+ _self.buildTree();
+ _self.setRadialLocations();
+ };
+ RadiaTreeLayout.prototype.checkHasCycle = function (node, pathNodes) {
+ var _self = this;
+ (node.outLinks || []).forEach(function (_link) {
+ var target = _link.target;
+ if (node.id == target.id || pathNodes.indexOf(target.id) != -1) {
+ _self.hasCycle = true;
+ return;
+ }
+ pathNodes.push(target.id);
+ _self.checkHasCycle(target, pathNodes);
+ });
+ };
+ RadiaTreeLayout.prototype.initNodeNeighbers = function (node) {
+ var _self = this;
+ var nodeNeighbers = [];
+ var outLinks = node.outLinks || [];
+ outLinks.forEach(function (link) {
+ var target = link.target;
+ if (node.id != target.id && target.visible) {
+ var index = _self.nodeIds.indexOf(target.id);
+ var childNodes = _self.nodeNeighbers[index] || [];
+ var childNodeIds = [];
+ childNodes.forEach(function (n) {
+ childNodeIds.push(n.id);
+ });
+ if (childNodeIds.indexOf(node.id) == -1) {
+ nodeNeighbers.push(target);
+ }
+ }
+ });
+ return nodeNeighbers;
+ };
+ RadiaTreeLayout.prototype.buildTree = function () {
+ var _self = this;
+ var roots = _self.getRoots();
+ if (roots.length > 0) {
+ _self.calculateRootsX(roots);
+ roots.forEach(function (node) {
+ _self.calculateNodeX(node);
+ _self.currentX += node.sizeT / 2 + _self.distX;
+ _self.buildNodeTree(node, _self.currentX);
+ });
+ }
+ };
+ RadiaTreeLayout.prototype.getRoots = function () {
+ var _self = this;
+ var roots = [];
+ _self.nodes.forEach(function (node) {
+ if ((node.inLinks || []).length == 0) {
+ roots.push(node);
+ }
+ });
+ return roots;
+ };
+ RadiaTreeLayout.prototype.calculateRootsX = function (roots) {
+ var _self = this;
+ var size = 0;
+ roots.forEach(function (node) {
+ var childNodes = _self.getSuccessors(node);
+ var childrenNum = childNodes.length;
+ if (childrenNum != 0) {
+ childNodes.forEach(function (node) {
+ size += _self.calculateNodeX(node) + _self.distX;
+ });
+ }
+ size = Math.max(0, size - _self.distX);
+ node.sizeT = size;
+ });
+ return size;
+ };
+ RadiaTreeLayout.prototype.calculateNodeX = function (node) {
+ var _self = this;
+ var size = 0;
+ var childNodes = _self.getSuccessors(node);
+ if (childNodes.length != 0) {
+ childNodes.forEach(function (_node) {
+ size += _self.calculateNodeX(_node) + _self.distX;
+ });
+ }
+ size = Math.max(0, size - _self.distX);
+ node.sizeT = size;
+ return size;
+ };
+ RadiaTreeLayout.prototype.buildNodeTree = function (node, x) {
+ var _self = this;
+ _self.currentY += _self.distY;
+ _self.currentX = x;
+ _self.setCurrentPositionFor(node);
+ var sizeXofCurrent = node.sizeT;
+ var lastX = x - sizeXofCurrent / 2;
+ var sizeXofChild;
+ var startXofChild;
+ var childNodes = _self.getSuccessors(node);
+ childNodes.forEach(function (n) {
+ sizeXofChild = n.sizeT;
+ startXofChild = lastX + sizeXofChild / 2;
+ _self.buildNodeTree(n, startXofChild);
+ lastX = lastX + sizeXofChild + _self.distX;
+ });
+ _self.currentY -= _self.distY;
+ };
+ RadiaTreeLayout.prototype.setCurrentPositionFor = function (node) {
+ var _self = this;
+ var x = _self.currentX;
+ var y = _self.currentY;
+ node.tempx = x;
+ node.tempy = y;
+ };
+ RadiaTreeLayout.prototype.getSuccessors = function (node) {
+ var _self = this;
+ var index = _self.nodeIds.indexOf(node.id);
+ var childNodes = _self.nodeNeighbers[index] || [];
+ return childNodes;
+ };
+ RadiaTreeLayout.prototype.setRadialLocations = function () {
+ var _self = this;
+ var maxPoint = _self.getMaxXY();
+ var maxx = maxPoint.x;
+ var maxy = maxPoint.y;
+ var theta = (2 * Math.PI) / maxx;
+ var deltaRadius = maxx / 2 / maxy;
+ _self.nodes.forEach(function (node) {
+ var _theta = node.tempx * theta;
+ var _raduis = (node.tempy - _self.distY) * deltaRadius;
+ var x = _raduis * Math.cos(_theta);
+ var y = _raduis * Math.sin(_theta);
+ var posData = _self.newLayoutData();
+ posData.finishx = x;
+ posData.finishy = y;
+ posData.xdistance = (1.0 / _self.intSteps) * (x - node.x);
+ posData.ydistance = (1.0 / _self.intSteps) * (y - node.y);
+ node.layoutData = posData;
+ });
+ };
+ RadiaTreeLayout.prototype.getMaxXY = function () {
+ var _self = this;
+ var maxx = 0,
+ maxy = 0;
+ _self.nodes.forEach(function (node) {
+ if (!node.tempx) {
+ node.tempx = _self.currentX;
+ }
+ if (!node.tempy) {
+ node.tempy = _self.currentY;
+ }
+ maxx = Math.max(maxx, node.tempx);
+ maxy = Math.max(maxy, node.tempy);
+ });
+ return { x: maxx, y: maxy };
+ };
+ RadiaTreeLayout.prototype.goAlgo = function () {
+ var _self = this;
+ var position = null;
+ var nodes = _self.nodes;
+ var length = nodes.length;
+ for (var i = 0; i < length; i++) {
+ var n = nodes[i];
+ position = n.layoutData;
+ if (position == null) {
+ continue;
+ }
+ if (_self.boolTransition) {
+ var currentDistance = Math.abs(n.x - position.finishx);
+ var nextDistance = Math.abs(
+ n.x + position.xdistance - position.finishx,
+ );
+ if (nextDistance < currentDistance) {
+ n.x += position.xdistance;
+ } else {
+ n.x = position.finishx;
+ }
+ currentDistance = Math.abs(n.y - position.finishy);
+ nextDistance = Math.abs(n.y + position.ydistance - position.finishy);
+ if (nextDistance < currentDistance) {
+ n.y += position.ydistance;
+ } else {
+ n.y = position.finishy;
+ }
+ if (n.x == position.finishx && n.y == position.finishy) {
+ n.layoutData = null;
+ }
+ } else {
+ n.x = position.finishx;
+ n.y = position.finishy;
+ n.layoutData = null;
+ }
+ }
+ };
+ var TopoTreeLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.raduis = 50;
+ this.boolTransition = true;
+ this.intSteps = 50;
+ this.hasCycle = false;
+ this.inited = false;
+ };
+ TopoTreeLayout.prototype.getConfig = function () {
+ return [{ label: "节点大小", raduis: 50 }];
+ };
+ TopoTreeLayout.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.raduis = Number(layoutConfig["raduis"]) || 50;
+ }
+ this.initAlgo();
+ };
+ TopoTreeLayout.prototype.initAlgo = function () {
+ var _self = this;
+ var roots = _self.getRoots();
+ roots[0].tempX = roots[0].x = 1000;
+ roots[0].tempY = roots[0].y = 500;
+ _self.countRadius(roots[0], _self.raduis);
+ _self.layout(roots[0], _self.raduis * 3);
+ this.inited = true;
+ };
+ TopoTreeLayout.prototype.countRadius = function (root, minR) {
+ var self = this;
+ minR = minR == null ? self.raduis : minR;
+ var children = self.getSuccessors(root);
+ var size = children.length;
+ if (size <= 1) {
+ root.rdegree = 0;
+ root.mradius = minR;
+ root.totalRadius = minR;
+ }
+ children.forEach(function (child) {
+ self.countRadius(child, minR);
+ });
+ if (size > 1) {
+ var child0 = children[0];
+ var totalRadius = child0.totalRadius;
+ if (size == 2) {
+ size = 3;
+ }
+ var degree = Math.PI / size;
+ var pRadius = totalRadius / Math.sin(degree);
+ root.mradius = pRadius;
+ root.totalRadius = pRadius + totalRadius;
+ root.rdegree = degree * 2;
+ }
+ };
+ TopoTreeLayout.prototype.layout = function (root, minR) {
+ var self = this;
+ var children = self.getSuccessors(root);
+ var len = children.length;
+ var degree = root.rdegree;
+ var r = root.mradius;
+ var rootPosition = { x: root.tempX, y: root.tempY };
+ children.forEach(function (node, index) {
+ var s = Math.sin(degree * index),
+ c = Math.cos(degree * index),
+ x = s * r,
+ y = c * r;
+ x = Math.round(x + rootPosition.x);
+ y = Math.round(y + rootPosition.y);
+ node.tempX = x;
+ node.tempY = y;
+ var posData = self.newLayoutData();
+ posData.finishx = x;
+ posData.finishy = y;
+ posData.xdistance = (1.0 / self.intSteps) * (x - node.x);
+ posData.ydistance = (1.0 / self.intSteps) * (y - node.y);
+ node.layoutData = posData;
+ self.layout(node, minR);
+ });
+ };
+ TopoTreeLayout.prototype.runLayout = function () {
+ if (!this.hasCycle && this.inited) {
+ this.goAlgo();
+ }
+ };
+ TopoTreeLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ TopoTreeLayout.prototype.getRoots = function () {
+ var _self = this;
+ var roots = [];
+ _self.nodes.forEach(function (node) {
+ if ((node.inLinks || []).length == 0) {
+ roots.push(node);
+ }
+ _self.checkHasCycle(node, []);
+ });
+ return roots;
+ };
+ TopoTreeLayout.prototype.checkHasCycle = function (node, pathNodes) {
+ var _self = this;
+ (node.outLinks || []).forEach(function (_link) {
+ var target = _link.target;
+ if (node.id == target.id || pathNodes.indexOf(target.id) != -1) {
+ _self.hasCycle = true;
+ return;
+ }
+ pathNodes.push(target.id);
+ _self.checkHasCycle(target, pathNodes);
+ });
+ };
+ TopoTreeLayout.prototype.getSuccessors = function (node) {
+ var _self = this;
+ var children = [];
+ if (!node) {
+ return children;
+ }
+ (node.outLinks || []).forEach(function (l) {
+ children.push(l.target);
+ });
+ return children;
+ };
+ TopoTreeLayout.prototype.goAlgo = function () {
+ var _self = this;
+ var position = null;
+ var nodes = _self.nodes;
+ var length = nodes.length;
+ for (var i = 0; i < length; i++) {
+ var n = nodes[i];
+ position = n.layoutData;
+ if (position == null) {
+ continue;
+ }
+ if (_self.boolTransition) {
+ var currentDistance = Math.abs(n.x - position.finishx);
+ var nextDistance = Math.abs(
+ n.x + position.xdistance - position.finishx,
+ );
+ if (nextDistance < currentDistance) {
+ n.x += position.xdistance;
+ } else {
+ n.x = position.finishx;
+ }
+ currentDistance = Math.abs(n.y - position.finishy);
+ nextDistance = Math.abs(n.y + position.ydistance - position.finishy);
+ if (nextDistance < currentDistance) {
+ n.y += position.ydistance;
+ } else {
+ n.y = position.finishy;
+ }
+ if (n.x == position.finishx && n.y == position.finishy) {
+ n.layoutData = null;
+ }
+ } else {
+ n.x = position.finishx;
+ n.y = position.finishy;
+ n.layoutData = null;
+ }
+ }
+ };
+ TopoTreeLayout.prototype.checkHasCycle = function (node, pathNodes) {
+ var _self = this;
+ (node.outLinks || []).forEach(function (_link) {
+ var target = _link.target;
+ if (node.id == target.id || pathNodes.indexOf(target.id) != -1) {
+ _self.hasCycle = true;
+ return;
+ }
+ pathNodes.push(target.id);
+ _self.checkHasCycle(target, pathNodes);
+ });
+ };
+ var ForceD3Layout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.size = [1400, 700];
+ this.alpha = 0.9;
+ this.friction = 0.9;
+ this.linkDistance = 120;
+ this.linkStrength = 0.09;
+ this.charge = -200;
+ this.gravity = 0.015;
+ this.theta = 0.8;
+ this.distances = [];
+ this.strengths = [];
+ this.charges = [];
+ this.noverlap = false;
+ this.inited = false;
+ };
+ ForceD3Layout.prototype.getConfig = function () {
+ return [
+ { label: "斥力", froce: 0.95 },
+ { label: "边长度", linkDistance: 150 },
+ { label: "边强度", linkStrength: 0.09 },
+ { label: "引力", charge: -300 },
+ { label: "重力", gravity: 0.015 },
+ {
+ label: "避免重叠",
+ noverlap: [
+ { label: "否", value: "false" },
+ { label: "是", value: "true" },
+ ],
+ },
+ ];
+ };
+ ForceD3Layout.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.friction = Number(layoutConfig["froce"]) || 0.95;
+ this.linkDistance = Number(layoutConfig["linkDistance"]) || 150;
+ this.linkStrength = Number(layoutConfig["linkStrength"]) || 0.09;
+ this.charge = Number(layoutConfig["charge"]) || -300;
+ this.gravity = Number(layoutConfig["gravity"]) || 0.015;
+ this.noverlap = layoutConfig["noverlap"] || "false";
+ this.size = layoutConfig["size"] || [1400, 700];
+ this.initAlgo();
+ }
+ };
+ ForceD3Layout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ ForceD3Layout.prototype.initAlgo = function () {
+ var _self = this;
+ var i,
+ j,
+ n = _self.nodes.length,
+ m = _self.links.length,
+ w = _self.size[0],
+ h = _self.size[1],
+ neighbors = [],
+ o;
+ _self.charges = [];
+ for (i = 0; i < n; ++i) {
+ (o = _self.nodes[i]).index = i;
+ o.weight = 0;
+ o.px = o.x;
+ o.py = o.y;
+ _self.charges[i] = _self.charge;
+ }
+ for (i = 0; i < m; ++i) {
+ o = _self.links[i];
+ var source = o.source;
+ var target = o.target;
+ _self.distances[i] = _self.linkDistance;
+ _self.strengths[i] = _self.linkStrength;
+ ++source.weight;
+ ++target.weight;
+ }
+ this.inited = true;
+ function position(dimension, size) {
+ var neighbors = neighbor(i),
+ j = -1,
+ m = neighbors.length,
+ x;
+ while (++j < m) {
+ if (!isNaN((x = neighbors[j][dimension]))) {
+ return x;
+ }
+ }
+ return Math.random() * size;
+ }
+ function neighbor() {
+ for (j = 0; j < n; ++j) {
+ neighbors[j] = [];
+ }
+ for (j = 0; j < m; ++j) {
+ var o = _self.links[j];
+ neighbors[o.source.index].push(o.target);
+ neighbors[o.target.index].push(o.source);
+ }
+ return neighbors[i];
+ }
+ return this.resume();
+ };
+ ForceD3Layout.prototype.goAlgo = function () {
+ this.tick();
+ };
+ ForceD3Layout.prototype.alpha1 = function (x) {
+ var _self = this;
+ if (!arguments.length) {
+ return _self.alpha;
+ }
+ if (_self.alpha) {
+ if (x > 0) {
+ _self.alpha = x;
+ } else {
+ _self.alpha = 0;
+ }
+ } else if (x > 0) {
+ _self.tick();
+ }
+ return this;
+ };
+ ForceD3Layout.prototype.resume = function () {
+ return this.alpha1(0.8);
+ };
+ ForceD3Layout.prototype.stop = function () {
+ return this.alpha1(0);
+ };
+ ForceD3Layout.prototype.tick = function () {
+ var _self = this;
+ if ((_self.alpha *= 0.99) < 0.0001) {
+ _self.alpha = 0.01;
+ return;
+ }
+ var n = _self.nodes.length,
+ m = _self.links.length,
+ q,
+ i,
+ o,
+ s,
+ t,
+ l,
+ k,
+ x,
+ y;
+ for (i = 0; i < m; ++i) {
+ o = _self.links[i];
+ s = o.source;
+ t = o.target;
+ x = t.x - s.x;
+ y = t.y - s.y;
+ if ((l = x * x + y * y)) {
+ l =
+ (_self.alpha *
+ _self.strengths[i] *
+ ((l = Math.sqrt(l)) - _self.distances[i])) /
+ l;
+ x *= l;
+ y *= l;
+ t.x -= x * (k = s.weight / (t.weight + s.weight));
+ t.y -= y * k;
+ s.x += x * (k = 1 - k);
+ s.y += y * k;
+ }
+ }
+ if ((k = _self.alpha * _self.gravity)) {
+ x = _self.size[0] / 2;
+ y = _self.size[1] / 2;
+ i = -1;
+ if (k) {
+ while (++i < n) {
+ o = _self.nodes[i];
+ o.x += (x - o.x) * k;
+ o.y += (y - o.y) * k;
+ }
+ }
+ }
+ if (_self.charge) {
+ _self.forceAccumulate(
+ (q = _self.quadtree(_self.nodes)),
+ _self.alpha,
+ _self.charges,
+ );
+ i = -1;
+ while (++i < n) {
+ if (!(o = _self.nodes[i]).fixed) {
+ q.visit(repulse(o));
+ }
+ }
+ }
+ i = -1;
+ while (++i < n) {
+ o = _self.nodes[i];
+ if (o.fixed) {
+ if (!o.isDragging) {
+ o.x = o.px;
+ o.y = o.py;
+ } else {
+ o.px = o.x;
+ o.py = o.y;
+ }
+ } else {
+ o.x -= (o.px - (o.px = o.x)) * _self.friction;
+ o.y -= (o.py - (o.py = o.y)) * _self.friction;
+ if (_self.noverlap == "true") {
+ q.visit(collide(o));
+ }
+ }
+ }
+ function repulse(node) {
+ return function (quad, x1, y1, x2, y2) {
+ if (quad.point !== node) {
+ var dx = quad.cx - node.x,
+ dy = quad.cy - node.y,
+ dn = 1 / Math.sqrt(dx * dx + dy * dy);
+ if ((x2 - x1) * dn < _self.theta) {
+ var k = quad.charge * dn * dn;
+ node.px -= dx * k;
+ node.py -= dy * k;
+ return true;
+ }
+ if (quad.point && isFinite(dn)) {
+ var k = quad.pointCharge * dn * dn;
+ node.px -= dx * k;
+ node.py -= dy * k;
+ }
+ }
+ return !quad.charge;
+ };
+ }
+ function collide(node) {
+ var r = node.radius * node.scaleX + 1,
+ nx1 = node.x - r,
+ nx2 = node.x + r,
+ ny1 = node.y - r,
+ ny2 = node.y + r;
+ return function (quad, x1, y1, x2, y2) {
+ if (quad.point && quad.point !== node) {
+ var x = node.x - quad.point.x,
+ y = node.y - quad.point.y,
+ l = Math.sqrt(x * x + y * y),
+ r = node.radius * node.scaleX + quad.point.radius;
+ if (l < r) {
+ l = ((l - r) / l) * 0.5;
+ node.x -= x *= l;
+ node.y -= y *= l;
+ quad.point.x += x;
+ quad.point.y += y;
+ }
+ }
+ return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
+ };
+ }
+ };
+ ForceD3Layout.prototype.forceAccumulate = function (quad, alpha, charges) {
+ var _self = this;
+ var cx = 0,
+ cy = 0;
+ quad.charge = 0;
+ if (!quad.leaf) {
+ var nodes = quad.nodes,
+ n = nodes.length,
+ i = -1,
+ c;
+ while (++i < n) {
+ c = nodes[i];
+ if (c == null) {
+ continue;
+ }
+ _self.forceAccumulate(c, alpha, charges);
+ quad.charge += c.charge;
+ cx += c.charge * c.cx;
+ cy += c.charge * c.cy;
+ }
+ }
+ if (quad.point) {
+ if (!quad.leaf) {
+ quad.point.x += Math.random() - 0.5;
+ quad.point.y += Math.random() - 0.5;
+ }
+ var k = _self.alpha * _self.charges[quad.point.index];
+ quad.charge += quad.pointCharge = k;
+ cx += k * quad.point.x;
+ cy += k * quad.point.y;
+ }
+ quad.cx = cx / quad.charge;
+ quad.cy = cy / quad.charge;
+ };
+ ForceD3Layout.prototype.quadtree = function (points, x1, y1, x2, y2) {
+ var _self = this;
+ var p,
+ i = -1,
+ n = points.length;
+ if (n && isNaN(points[0].x)) {
+ points = points.map(function (p) {
+ return { x: p[0], y: p[1] };
+ });
+ }
+ if (arguments.length < 5) {
+ if (arguments.length === 3) {
+ y2 = x2 = y1;
+ y1 = x1;
+ } else {
+ x1 = y1 = Infinity;
+ x2 = y2 = -Infinity;
+ while (++i < n) {
+ p = points[i];
+ if (p.x < x1) {
+ x1 = p.x;
+ }
+ if (p.y < y1) {
+ y1 = p.y;
+ }
+ if (p.x > x2) {
+ x2 = p.x;
+ }
+ if (p.y > y2) {
+ y2 = p.y;
+ }
+ }
+ var dx = x2 - x1,
+ dy = y2 - y1;
+ if (dx > dy) {
+ y2 = y1 + dx;
+ } else {
+ x2 = x1 + dy;
+ }
+ }
+ }
+ function insert(n, p, x1, y1, x2, y2) {
+ if (isNaN(p.x) || isNaN(p.y)) {
+ return;
+ }
+ if (n.leaf) {
+ var v = n.point;
+ if (v) {
+ if (Math.abs(v.x - p.x) + Math.abs(v.y - p.y) < 0.01) {
+ insertChild(n, p, x1, y1, x2, y2);
+ } else {
+ n.point = null;
+ insertChild(n, v, x1, y1, x2, y2);
+ insertChild(n, p, x1, y1, x2, y2);
+ }
+ } else {
+ n.point = p;
+ }
+ } else {
+ insertChild(n, p, x1, y1, x2, y2);
+ }
+ }
+ function insertChild(n, p, x1, y1, x2, y2) {
+ var sx = (x1 + x2) * 0.5,
+ sy = (y1 + y2) * 0.5,
+ right = p.x >= sx,
+ bottom = p.y >= sy,
+ i = (bottom << 1) + right;
+ n.leaf = false;
+ n = n.nodes[i] || (n.nodes[i] = { leaf: true, nodes: [], point: null });
+ if (right) {
+ x1 = sx;
+ } else {
+ x2 = sx;
+ }
+ if (bottom) {
+ y1 = sy;
+ } else {
+ y2 = sy;
+ }
+ insert(n, p, x1, y1, x2, y2);
+ }
+ function quadtreeVisit(f, node, x1, y1, x2, y2) {
+ if (!f(node, x1, y1, x2, y2)) {
+ var sx = (x1 + x2) * 0.5,
+ sy = (y1 + y2) * 0.5,
+ children = node.nodes;
+ if (children[0]) {
+ quadtreeVisit(f, children[0], x1, y1, sx, sy);
+ }
+ if (children[1]) {
+ quadtreeVisit(f, children[1], sx, y1, x2, sy);
+ }
+ if (children[2]) {
+ quadtreeVisit(f, children[2], x1, sy, sx, y2);
+ }
+ if (children[3]) {
+ quadtreeVisit(f, children[3], sx, sy, x2, y2);
+ }
+ }
+ }
+ var root = { leaf: true, nodes: [], point: null };
+ root.add = function (p) {
+ insert(root, p, x1, y1, x2, y2);
+ };
+ root.visit = function (f) {
+ quadtreeVisit(f, root, x1, y1, x2, y2);
+ };
+ points.forEach(root.add);
+ return root;
+ };
+ var ForceDirected = function (_nodes, _links) {
+ this.nodes = _nodes;
+ this.links = _links;
+ this.attraction_multiplier = 5;
+ this.repulsion_multiplier = 0.5;
+ this.width = 1200;
+ this.height = 800;
+ this.inited = false;
+ var EPSILON = 1 / 100000;
+ var attraction_constant;
+ var repulsion_constant;
+ var forceConstant;
+ var layout_iterations = 0;
+ var max_iterations = 100000;
+ var temperature = 0;
+ var scalar = 10;
+ var that = this;
+ var nodes_length = _nodes.length;
+ var links_length = _links.length;
+ this.getConfig = function () {
+ return [
+ { label: "吸引力", attraction: 2 },
+ { label: "斥力", force: 100 },
+ ];
+ };
+ this.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ attraction_multiplier = Number(layoutConfig["attraction"]) || 2;
+ forceConstant = Number(layoutConfig["force"]) || 100;
+ var size = layoutConfig["size"] || [1200, 800];
+ this.width = size[0];
+ this.height = size[1];
+ that.initAlgo();
+ }
+ };
+ this.initAlgo = function () {
+ temperature = 10.0;
+ layout_iterations = 0;
+ attraction_constant = that.attraction_multiplier * forceConstant;
+ repulsion_constant = that.repulsion_multiplier * forceConstant;
+ that.inited = true;
+ };
+ this.runLayout = function () {
+ if (that.inited) {
+ that.goAlgo();
+ }
+ };
+ this.goAlgo = function () {
+ if (temperature > 1 / 100000) {
+ var i, j, delta, delta_length, force, change;
+ for (i = 0; i < nodes_length; i++) {
+ var node_v = that.nodes[i];
+ node_v.layout = node_v.layout || {};
+ if (i === 0) {
+ node_v.layout.offset = new Vector2();
+ }
+ node_v.layout.force = 0;
+ node_v.layout.tmp_pos =
+ node_v.layout.tmp_pos || new Vector2().setVector(node_v);
+ for (j = i + 1; j < nodes_length; j++) {
+ var node_u = that.nodes[j];
+ if (i != j) {
+ node_u.layout = node_u.layout || {};
+ node_u.layout.tmp_pos =
+ node_u.layout.tmp_pos || new Vector2().setVector(node_u);
+ delta = node_v.layout.tmp_pos.clone().sub(node_u.layout.tmp_pos);
+ delta_length = Math.max(
+ EPSILON,
+ Math.sqrt(delta.clone().multiply(delta).sum()),
+ );
+ force = (repulsion_constant * repulsion_constant) / delta_length;
+ node_v.layout.force += force;
+ node_u.layout.force += force;
+ if (i === 0) {
+ node_u.layout.offset = new Vector2();
+ }
+ change = delta
+ .clone()
+ .multiply(new Vector2().setScalar(force / delta_length));
+ node_v.layout.offset.add(change);
+ node_u.layout.offset.sub(change);
+ }
+ }
+ }
+ for (i = 0; i < links_length; i++) {
+ var link = that.links[i];
+ delta = link.source.layout.tmp_pos
+ .clone()
+ .sub(link.target.layout.tmp_pos);
+ delta_length = Math.max(
+ EPSILON,
+ Math.sqrt(delta.clone().multiply(delta).sum()),
+ );
+ force = (delta_length * delta_length) / attraction_constant;
+ link.source.layout.force -= force;
+ link.target.layout.force += force;
+ change = delta
+ .clone()
+ .multiply(new Vector2().setScalar(force / delta_length));
+ link.target.layout.offset.add(change);
+ link.source.layout.offset.sub(change);
+ }
+ for (i = 0; i < nodes_length; i++) {
+ var node = that.nodes[i];
+ delta_length = Math.max(
+ EPSILON,
+ Math.sqrt(
+ node.layout.offset.clone().multiply(node.layout.offset).sum(),
+ ),
+ );
+ node.layout.tmp_pos.add(
+ node.layout.offset
+ .clone()
+ .multiply(
+ new Vector2().setScalar(
+ Math.min(delta_length, temperature) / delta_length,
+ ),
+ ),
+ );
+ var tmpPosition = new Vector2(node.x, node.y, 0);
+ tmpPosition
+ .sub(node.layout.tmp_pos)
+ .divide(new Vector2().setScalar(scalar));
+ node.x -= tmpPosition.x;
+ node.y -= tmpPosition.y;
+ }
+ temperature *= 1 - layout_iterations / max_iterations;
+ layout_iterations++;
+ }
+ };
+ };
+ function Vector2(x, y) {
+ this.x = x || 0;
+ this.y = y || 0;
+ }
+ Object.assign(Vector2.prototype, {
+ set: function (x, y) {
+ this.x = x;
+ this.y = y;
+ return this;
+ },
+ setScalar: function (scalar) {
+ this.x = scalar;
+ this.y = scalar;
+ return this;
+ },
+ setVector: function (v) {
+ this.x = v.x || 0;
+ this.y = v.y || 0;
+ return this;
+ },
+ clone: function () {
+ return new this.constructor(this.x, this.y, this.z);
+ },
+ add: function (v) {
+ this.x += v.x;
+ this.y += v.y;
+ return this;
+ },
+ addScalar: function (s) {
+ this.x += s;
+ this.y += s;
+ return this;
+ },
+ sub: function (v) {
+ this.x -= v.x;
+ this.y -= v.y;
+ return this;
+ },
+ multiply: function (v) {
+ this.x *= v.x;
+ this.y *= v.y;
+ return this;
+ },
+ divide: function (v) {
+ this.x /= v.x;
+ this.y /= v.y;
+ return this;
+ },
+ sum: function () {
+ return this.x + this.y;
+ },
+ equals: function (v) {
+ return v.x === this.x && v.y === this.y;
+ },
+ });
+ var HierarchicalLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.layerDistance = 100;
+ this.nodeDistance = 60;
+ this.treeSpacing = 0;
+ this.direction = "UD";
+ this.sortMethod = "hubsize";
+ this.treeIndex = -1;
+ this.continueOrBreak = 0;
+ this.boolTransition = true;
+ this.inited = false;
+ };
+ HierarchicalLayout.prototype.getConfig = function () {
+ return [
+ { label: "层间距", layerDistance: 100 },
+ { label: "点间距", nodeDistance: 100 },
+ {
+ label: "排列方式",
+ sortMethod: [
+ { label: "连线方向", value: "directed" },
+ { label: "度大小", value: "hubsize" },
+ { label: "指定点", value: "selected" },
+ ],
+ },
+ {
+ label: "排列方向",
+ direction: [
+ { label: "上下", value: "UD" },
+ { label: "下上", value: "DU" },
+ { label: "左右", value: "LR" },
+ { label: "右左", value: "RL" },
+ ],
+ },
+ ];
+ };
+ HierarchicalLayout.prototype.resetConfig = function (layoutConfig) {
+ var self = this;
+ if (layoutConfig) {
+ self.layerDistance = Number(layoutConfig["layerDistance"]) || 100;
+ self.nodeDistance = Number(layoutConfig["nodeDistance"]) || 80;
+ self.sortMethod = layoutConfig["sortMethod"] || "hubsize";
+ self.direction = layoutConfig["direction"] || "UD";
+ }
+ self.initAlgo();
+ };
+ HierarchicalLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ HierarchicalLayout.prototype.initAlgo = function () {
+ var self = this;
+ self.treeIndex = -1;
+ self.continueOrBreak = 0;
+ self.nodeIdList = [];
+ self.selectedNodeIds = null;
+ self.positionedNodes = {};
+ self.hierarchicalLevels = {};
+ self.hierarchicalTrees = {};
+ self.lastNodeOnLevel = {};
+ self.hierarchicalChildrenReference = {};
+ self.hierarchicalParentReference = {};
+ self.distributionIndex = {};
+ self.distributionOrdering = {};
+ self.distributionOrderingPresence = {};
+ self.nodesIdMap = {};
+ self.edges = {};
+ self.setData();
+ self.setupHierarchicalLayout();
+ self.nodes.forEach(function (node) {
+ var nodeId = String(node.id);
+ var nodeLocal = self.nodesIdMap[nodeId];
+ var x = 0,
+ y = 0;
+ if (self.direction == "DU") {
+ x = nodeLocal.x;
+ y = -nodeLocal.y;
+ } else if (self.direction == "RL") {
+ x = -nodeLocal.x;
+ y = nodeLocal.y;
+ } else {
+ x = nodeLocal.x;
+ y = nodeLocal.y;
+ }
+ var posData = self.newLayoutData();
+ posData.finishx = x;
+ posData.finishy = y;
+ posData.xdistance = (1.0 / 50) * (x - node.x);
+ posData.ydistance = (1.0 / 50) * (y - node.y);
+ node.layoutData = posData;
+ });
+ self.inited = true;
+ };
+ HierarchicalLayout.prototype.setData = function (selectedNodeId) {
+ var self = this;
+ self.nodes.forEach(function (node) {
+ var nodeId = String(node.id);
+ var nodeTemp = self.NodeLocal(nodeId);
+ self.nodesIdMap[nodeId] = nodeTemp;
+ self.nodeIdList.push(nodeId);
+ });
+ self.links.forEach(function (edge, i) {
+ var id = String(i + 1);
+ var edgeLocal = self.Edge(edge.source.id, edge.target.id, id);
+ self.edges[id] = edgeLocal;
+ var fromId = edgeLocal.fromId;
+ var toId = edgeLocal.toId;
+ var fromNode = self.nodesIdMap[fromId];
+ if (fromNode.edgesIds.indexOf(id) == -1) {
+ fromNode.edgesIds.push(id);
+ }
+ var toNode = self.nodesIdMap[toId];
+ if (toNode.edgesIds.indexOf(id) == -1) {
+ toNode.edgesIds.push(id);
+ }
+ });
+ if (self.sortMethod == "selected") {
+ var selectedNodes = self.nodes.filter(function (n) {
+ return n.selected == true;
+ });
+ var _selectedNodeIds = selectedNodes.map((n) => {
+ return String(n.id);
+ });
+ self.selectedNodeIds = _selectedNodeIds;
+ }
+ };
+ HierarchicalLayout.prototype.setupHierarchicalLayout = function () {
+ var self = this;
+ if (self.sortMethod == "hubsize") {
+ self.determineLevelsByHubsize();
+ } else if (self.sortMethod == "directed") {
+ self.determineLevelsByDirected();
+ } else if (self.sortMethod == "selected") {
+ self.determineLevelsBySelected();
+ }
+ self.nodeIdList.forEach(function (nodeId) {
+ if (self.hierarchicalLevels[nodeId] == null) {
+ self.hierarchicalLevels[nodeId] = 0;
+ }
+ });
+ var distribution = self.getDistribution();
+ self.crawlNetwork("generateMap", -1);
+ self.placeNodesByHierarchy(distribution);
+ self.condenseHierarchy();
+ };
+ HierarchicalLayout.prototype.determineLevelsByDirected = function () {
+ var self = this;
+ self.crawlNetwork("determineLevelsByDirected", -1);
+ var minLevel = 1000000000;
+ self.nodeIdList.forEach(function (nodeId) {
+ if (self.hierarchicalLevels[nodeId] != null) {
+ minLevel = Math.min(self.hierarchicalLevels[nodeId], minLevel);
+ }
+ });
+ self.nodeIdList.forEach(function (nodeId) {
+ if (self.hierarchicalLevels[nodeId] != null) {
+ self.hierarchicalLevels[nodeId] =
+ self.hierarchicalLevels[nodeId] - minLevel;
+ }
+ });
+ };
+ HierarchicalLayout.prototype.determineLevelsBySelected = function () {
+ var self = this;
+ if (self.selectedNodeIds == null) {
+ self.determineLevelsByHubsize();
+ } else {
+ self.selectedNodeIds.forEach(function (nodeId) {
+ self.hierarchicalLevels[nodeId] = 0;
+ });
+ self.selectedNodeIds.forEach(function (nodeId) {
+ if (self.nodesIdMap[nodeId] != null) {
+ self.crawlNetwork("determineLevelsByHubsize", nodeId);
+ }
+ });
+ self.determineLevelsByHubsize();
+ }
+ };
+ HierarchicalLayout.prototype.NodeLocal = function (nodeId) {
+ return { id: nodeId, edgesIds: [], x: 0.5, y: 0.5 };
+ };
+ HierarchicalLayout.prototype.Edge = function (fromId, toId, id) {
+ return { id: id, fromId: fromId, toId: toId };
+ };
+ HierarchicalLayout.prototype.determineLevelsByHubsize = function () {
+ var self = this;
+ var hubSize = 1;
+ while (hubSize > 0) {
+ var _hubSize = 0;
+ self.nodeIdList.forEach(function (nodeId) {
+ var node = self.nodesIdMap[nodeId];
+ if (self.hierarchicalLevels[node.id] == null) {
+ _hubSize =
+ node.edgesIds.length < _hubSize ? _hubSize : node.edgesIds.length;
+ }
+ });
+ hubSize = _hubSize;
+ if (hubSize == 0) {
+ return;
+ }
+ self.nodeIdList.forEach(function (nodeId) {
+ var node = self.nodesIdMap[nodeId];
+ if (node.edgesIds.length == hubSize) {
+ self.crawlNetwork("determineLevelsByHubsize", node.id);
+ }
+ });
+ }
+ };
+ HierarchicalLayout.prototype.condenseHierarchy = function () {
+ var self = this;
+ var minPre = 1000000000,
+ maxPre = -1000000000;
+ var minAfter = 1000000000,
+ maxAfter = -1000000000;
+ for (var i = 0; i < self.treeIndex; i++) {
+ for (var nodeId in self.hierarchicalTrees) {
+ if (i == 0 && self.hierarchicalTrees[nodeId] == i) {
+ var pos = self.getPositionForHierarchy(self.nodesIdMap[nodeId]);
+ minPre = Math.min(pos, minPre);
+ maxPre = Math.max(pos, maxPre);
+ }
+ if (self.hierarchicalTrees[nodeId] == i + 1) {
+ var pos = self.getPositionForHierarchy(self.nodesIdMap[nodeId]);
+ minAfter = Math.min(pos, minAfter);
+ maxAfter = Math.max(pos, maxAfter);
+ }
+ }
+ var diff = 0;
+ for (var nodeId in self.hierarchicalTrees) {
+ if (self.hierarchicalTrees[nodeId] == i + 1) {
+ var node = self.nodesIdMap[nodeId];
+ var pos = self.getPositionForHierarchy(node);
+ self.setPositionForHierarchy(node, pos + diff + self.treeSpacing, -1);
+ }
+ }
+ minPre = minAfter + diff + self.treeSpacing;
+ maxPre = maxAfter + diff + self.treeSpacing;
+ }
+ };
+ HierarchicalLayout.prototype.shiftToCenter = function () {
+ var self = this;
+ var minY = 1000000000,
+ maxY = -1000000000;
+ var minX = 1000000000,
+ maxX = -1000000000;
+ self.nodeIdList.forEach(function (nodeId) {
+ var node = self.nodesIdMap[nodeId];
+ minX = Math.min(minX, node.x);
+ maxX = Math.max(maxX, node.x);
+ minY = Math.min(minY, node.y);
+ maxY = Math.max(maxY, node.y);
+ });
+ var width = maxX - minX;
+ var height = maxY - minY;
+ var ratioW = 1,
+ ratioH = 1;
+ var standardW = 5000,
+ standardH = 3000;
+ if (width > standardW) {
+ ratioW = standardW / width;
+ }
+ if (height > standardH) {
+ ratioH = standardH / height;
+ }
+ self.nodeIdList.forEach(function (nodeId) {
+ var node = self.nodesIdMap[nodeId];
+ var nodeX = node.x;
+ node.x = Math.round((nodeX - minX) * ratioW);
+ var nodeY = node.y;
+ node.y = Math.round((nodeY - minY) * ratioH);
+ });
+ };
+ HierarchicalLayout.prototype.getDistribution = function () {
+ var self = this;
+ var distribution = {};
+ self.nodeIdList.forEach(function (nodeId) {
+ var node = self.nodesIdMap[nodeId];
+ var level =
+ self.hierarchicalLevels[nodeId] == null
+ ? 1
+ : self.hierarchicalLevels[nodeId];
+ if (self.direction == "UD" || self.direction == "DU") {
+ node.y = self.layerDistance * level;
+ } else {
+ node.x = self.layerDistance * level;
+ }
+ var temp = distribution[level];
+ if (temp == null) {
+ temp = [];
+ }
+ temp.push(node);
+ distribution[level] = temp;
+ });
+ return distribution;
+ };
+ HierarchicalLayout.prototype.crawlNetwork = function (callbackFlag, nodeId) {
+ var self = this;
+ var startingNodeId = nodeId;
+ var progress = {};
+ if (startingNodeId == -1) {
+ var _treeIndex = 0;
+ self.nodeIdList.forEach(function (id) {
+ var node = self.nodesIdMap[id];
+ if (progress[id] == null) {
+ progress = self.crawler(progress, node, callbackFlag, _treeIndex);
+ }
+ _treeIndex++;
+ });
+ } else {
+ var node = self.nodesIdMap[startingNodeId];
+ progress = self.crawler(progress, node, callbackFlag, -111);
+ }
+ };
+ HierarchicalLayout.prototype.crawler = function (
+ progress,
+ node,
+ callbackFlag,
+ _treeIndex,
+ ) {
+ var self = this;
+ if (progress[node.id] == null) {
+ if (_treeIndex != -111) {
+ if (self.hierarchicalTrees[node.id] == null) {
+ self.hierarchicalTrees[node.id] = _treeIndex;
+ self.treeIndex = Math.max(_treeIndex, self.treeIndex);
+ }
+ }
+ progress[node.id] = true;
+ var edgesIdsLength = node.edgesIds.length;
+ for (var i = 0; i < edgesIdsLength; i++) {
+ var edgeId = node.edgesIds[i];
+ var edge = self.edges[edgeId];
+ var childNode = null;
+ if (edge.toId == node.id) {
+ childNode = self.nodesIdMap[edge.fromId];
+ } else {
+ childNode = self.nodesIdMap[edge.toId];
+ }
+ if (childNode != null && node.id != childNode.id) {
+ if (callbackFlag == "determineLevelsByHubsize") {
+ self.levelDownstream(node, childNode);
+ } else if (callbackFlag == "determineLevelsByDirected") {
+ self.levelByDirection(node, childNode, edge);
+ } else if (callbackFlag == "generateMap") {
+ self.fillInRelations(node, childNode);
+ }
+ self.crawler(progress, childNode, callbackFlag, _treeIndex);
+ }
+ }
+ }
+ return progress;
+ };
+ HierarchicalLayout.prototype.levelDownstream = function (source, nodeB) {
+ var self = this;
+ if (self.hierarchicalLevels[nodeB.id] == null) {
+ if (self.hierarchicalLevels[source.id] == null) {
+ self.hierarchicalLevels[source.id] = 0;
+ }
+ self.hierarchicalLevels[nodeB.id] =
+ self.hierarchicalLevels[source.id] + 1;
+ }
+ };
+ HierarchicalLayout.prototype.levelByDirection = function (
+ source,
+ nodeB,
+ edge,
+ ) {
+ var self = this;
+ if (self.hierarchicalLevels[source.id] == null) {
+ self.hierarchicalLevels[source.id] = 1;
+ }
+ if (self.hierarchicalLevels[nodeB.id] == null) {
+ self.hierarchicalLevels[nodeB.id] =
+ self.hierarchicalLevels[source.id] + 1;
+ }
+ };
+ HierarchicalLayout.prototype.fillInRelations = function (
+ parentNode,
+ childNode,
+ ) {
+ var self = this;
+ if (
+ self.hierarchicalLevels[childNode.id] >
+ self.hierarchicalLevels[parentNode.id]
+ ) {
+ if (self.hierarchicalChildrenReference[parentNode.id] == null) {
+ self.hierarchicalChildrenReference[parentNode.id] = [];
+ }
+ self.hierarchicalChildrenReference[parentNode.id].push(childNode.id);
+ if (self.hierarchicalParentReference[childNode.id] == null) {
+ self.hierarchicalParentReference[childNode.id] = [];
+ }
+ self.hierarchicalParentReference[childNode.id].push(parentNode.id);
+ }
+ };
+ HierarchicalLayout.prototype.placeNodesByHierarchy = function (distribution) {
+ var self = this;
+ for (var nodeId in distribution) {
+ var nodesList = distribution[nodeId];
+ var handledNodeCount = 0;
+ var nodesListLength = nodesList.length;
+ for (var i = 0; i < nodesListLength; i++) {
+ var node = nodesList[i];
+ if (self.positionedNodes[node.id] == null) {
+ var pos = self.nodeDistance * handledNodeCount;
+ if (handledNodeCount > 0) {
+ pos =
+ self.getPositionForHierarchy(nodesList[i - 1]) +
+ self.nodeDistance;
+ }
+ self.setPositionForHierarchy(node, pos, nodeId);
+ self.validataPositionAndContinue(node, nodeId, pos);
+ handledNodeCount++;
+ }
+ }
+ }
+ };
+ HierarchicalLayout.prototype.getPositionForHierarchy = function (node) {
+ if (this.direction == "UD" || this.direction == "DU") {
+ return node.x;
+ }
+ return node.y;
+ };
+ HierarchicalLayout.prototype.setPositionForHierarchy = function (
+ node,
+ position,
+ level,
+ ) {
+ var self = this;
+ if (level != -1) {
+ if (self.distributionOrdering[level] == null) {
+ self.distributionOrdering[level] = [];
+ self.distributionOrderingPresence[level] = {};
+ }
+ if (self.distributionOrderingPresence[level][node.id] == null) {
+ self.distributionOrdering[level].push(node);
+ self.distributionIndex[node.id] =
+ self.distributionOrdering[level].length - 1;
+ }
+ self.distributionOrderingPresence[level][node.id] = true;
+ }
+ if (self.direction == "UD" || self.direction == "DU") {
+ node.x = position;
+ } else {
+ node.y = position;
+ }
+ };
+ HierarchicalLayout.prototype.shiftBlock = function (parentId, diff) {
+ var self = this;
+ if (self.direction == "UD" || self.direction == "DU") {
+ self.nodesIdMap[parentId].x += diff;
+ } else {
+ self.nodesIdMap[parentId].y += diff;
+ }
+ };
+ HierarchicalLayout.prototype.placeBranchNodes = function (
+ parentNode,
+ parentLevel,
+ ) {
+ var self = this;
+ if (self.hierarchicalChildrenReference[parentNode.id] == null) {
+ return;
+ }
+ var childNodes = [];
+ var length = self.hierarchicalChildrenReference[parentNode.id].length;
+ for (var i = 0; i < length; i++) {
+ childNodes.push(
+ self.nodesIdMap[self.hierarchicalChildrenReference[parentNode.id][i]],
+ );
+ }
+ var childNodesLength = childNodes.length;
+ for (var i = 0; i < childNodesLength; i++) {
+ var childNode = childNodes[i];
+ var childNodeLevel = self.hierarchicalLevels[childNode.id];
+ if (
+ childNodeLevel > parentLevel &&
+ self.positionedNodes[childNode.id] == null
+ ) {
+ var pos = 0;
+ if (i == 0) {
+ pos = self.getPositionForHierarchy(self.nodesIdMap[parentNode.id]);
+ } else {
+ pos =
+ self.getPositionForHierarchy(childNodes[i - 1]) + self.nodeDistance;
+ }
+ self.setPositionForHierarchy(childNode, pos, childNodeLevel);
+ self.validataPositionAndContinue(childNode, childNodeLevel, pos);
+ }
+ }
+ var minPos = 1000000000,
+ maxPos = -1000000000;
+ for (var i = 0; i < childNodesLength; i++) {
+ var childNode = childNodes[i];
+ minPos = Math.min(minPos, self.getPositionForHierarchy(childNode));
+ maxPos = Math.max(maxPos, self.getPositionForHierarchy(childNode));
+ }
+ var _pos = (minPos + maxPos) / 2;
+ self.setPositionForHierarchy(parentNode, _pos, parentLevel);
+ };
+ HierarchicalLayout.prototype.validataPositionAndContinue = function (
+ node,
+ nodeId,
+ pos,
+ ) {
+ var self = this;
+ if (self.lastNodeOnLevel[nodeId] != undefined) {
+ var previousPos = self.getPositionForHierarchy(
+ self.nodesIdMap[self.lastNodeOnLevel[nodeId]],
+ );
+ if (pos - previousPos < self.nodeDistance) {
+ var diff = previousPos + self.nodeDistance - pos;
+ self.shiftBlock(node.id, diff);
+ }
+ }
+ self.lastNodeOnLevel[nodeId] = node.id;
+ self.positionedNodes[node.id] = true;
+ self.placeBranchNodes(node, nodeId);
+ };
+ HierarchicalLayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ HierarchicalLayout.prototype.goAlgo = function () {
+ var self = this;
+ var position = null;
+ var nodes = self.nodes;
+ var length = nodes.length;
+ for (var i = 0; i < length; i++) {
+ var n = nodes[i];
+ position = n.layoutData;
+ if (position == null) {
+ continue;
+ }
+ if (self.boolTransition) {
+ var currentDistance = Math.abs(n.x - position.finishx);
+ var nextDistance = Math.abs(
+ n.x + position.xdistance - position.finishx,
+ );
+ if (nextDistance < currentDistance) {
+ n.x += position.xdistance;
+ } else {
+ n.x = position.finishx;
+ }
+ currentDistance = Math.abs(n.y - position.finishy);
+ nextDistance = Math.abs(n.y + position.ydistance - position.finishy);
+ if (nextDistance < currentDistance) {
+ n.y += position.ydistance;
+ } else {
+ n.y = position.finishy;
+ }
+ if (n.x == position.finishx && n.y == position.finishy) {
+ n.layoutData = null;
+ }
+ } else {
+ n.x = position.finishx;
+ n.y = position.finishy;
+ n.layoutData = null;
+ }
+ }
+ };
+ var HiveLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.margin = 0;
+ this.radius = 50;
+ this.nlines = 5;
+ this.boolTransition = true;
+ this.intSteps = 50;
+ this.inited = false;
+ };
+ HiveLayout.prototype.getConfig = function () {
+ return [{ label: "分支数", nlines: 5 }];
+ };
+ HiveLayout.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.nlines = Number(layoutConfig["nlines"]) || 5;
+ }
+ this.initAlgo();
+ };
+ HiveLayout.prototype.newLayoutData = function () {
+ var layoutData = {
+ finishx: 0.0,
+ finishy: 0.0,
+ xdistance: 0.0,
+ ydistance: 0.0,
+ };
+ return layoutData;
+ };
+ HiveLayout.prototype.initAlgo = function () {
+ var self = this;
+ var nodeCount = Math.max(this.nodes.length * 6, 1200);
+ const nodes_segment = this.nodes.length / this.nlines;
+ const segment = nodeCount - (this.margin + this.radius);
+ const step = segment / nodes_segment;
+ const angle = (2 * Math.PI) / this.nlines;
+ let j = 0;
+ for (let i = 0; i < this.nodes.length; ++i) {
+ var node = this.nodes[i];
+ var x =
+ nodeCount +
+ (this.radius + step * (i - j * nodes_segment)) *
+ Math.cos(angle * j + Math.PI / 2);
+ var y =
+ nodeCount +
+ (this.radius + step * (i - j * nodes_segment)) *
+ Math.sin(angle * j + Math.PI / 2);
+ j = Math.floor(i / nodes_segment);
+ var posData = self.newLayoutData();
+ posData.finishx = x;
+ posData.finishy = y;
+ posData.xdistance = (1.0 / self.intSteps) * (x - node.x);
+ posData.ydistance = (1.0 / self.intSteps) * (y - node.y);
+ node.layoutData = posData;
+ }
+ this.inited = true;
+ };
+ HiveLayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ HiveLayout.prototype.goAlgo = function () {
+ var self = this;
+ var position = null;
+ var nodes = self.nodes;
+ var length = nodes.length;
+ for (var i = 0; i < length; i++) {
+ var n = nodes[i];
+ position = n.layoutData;
+ if (position == null) {
+ continue;
+ }
+ if (self.boolTransition) {
+ var currentDistance = Math.abs(n.x - position.finishx);
+ var nextDistance = Math.abs(
+ n.x + position.xdistance - position.finishx,
+ );
+ if (nextDistance < currentDistance) {
+ n.x += position.xdistance;
+ } else {
+ n.x = position.finishx;
+ }
+ currentDistance = Math.abs(n.y - position.finishy);
+ nextDistance = Math.abs(n.y + position.ydistance - position.finishy);
+ if (nextDistance < currentDistance) {
+ n.y += position.ydistance;
+ } else {
+ n.y = position.finishy;
+ }
+ if (n.x == position.finishx && n.y == position.finishy) {
+ n.layoutData = null;
+ }
+ } else {
+ n.x = position.finishx;
+ n.y = position.finishy;
+ n.layoutData = null;
+ }
+ }
+ };
+ var AvoidOverlapLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.maxPadding = 10;
+ this.inited = false;
+ this.maxIterations = 0;
+ };
+ AvoidOverlapLayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ AvoidOverlapLayout.prototype.getConfig = function () {
+ var self = this;
+ return [{ label: "间距", maxPadding: self.maxPadding }];
+ };
+ AvoidOverlapLayout.prototype.resetConfig = function (layoutConfig) {
+ this.initAlgo();
+ if (layoutConfig) {
+ this.maxPadding = Number(layoutConfig["maxPadding"]) || 2;
+ if (this.maxPadding < 0) {
+ this.maxPadding = 0;
+ }
+ }
+ };
+ AvoidOverlapLayout.prototype.initAlgo = function () {
+ this.inited = true;
+ this.maxIterations = 0;
+ };
+ AvoidOverlapLayout.prototype.goAlgo = function () {
+ var self = this;
+ if (this.inited) {
+ if (this.maxIterations++ < this.nodes.length / 4) {
+ var q = this.quadtree(this.nodes);
+ self.nodes.forEach(function (_node) {
+ q.visit(collide(_node));
+ });
+ }
+ }
+ function collide(node) {
+ var nr = node.radius * node.scaleX * 2 + self.maxPadding,
+ nx1 = node.x - nr,
+ nx2 = node.x + nr,
+ ny1 = node.y - nr,
+ ny2 = node.y + nr;
+ return function (quad, x1, y1, x2, y2) {
+ if (quad.point && quad.point !== node) {
+ var x = node.x - quad.point.x,
+ y = node.y - quad.point.y,
+ l = Math.sqrt(x * x + y * y),
+ r = nr + quad.point.radius;
+ if (l < r) {
+ l = ((l - r) / l) * 0.5;
+ node.x -= x *= l;
+ node.y -= y *= l;
+ quad.point.x += x;
+ quad.point.y += y;
+ }
+ }
+ return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
+ };
+ }
+ };
+ AvoidOverlapLayout.prototype.quadtree = function (points) {
+ var p,
+ i = -1,
+ n = points.length;
+ if (n && isNaN(points[0].x)) {
+ points = points.map(function (p) {
+ return { x: p[0], y: p[1] };
+ });
+ }
+ var x1 = (y1 = Infinity);
+ var x2 = (y2 = -Infinity);
+ while (++i < n) {
+ p = points[i];
+ if (p.x < x1) {
+ x1 = p.x;
+ }
+ if (p.y < y1) {
+ y1 = p.y;
+ }
+ if (p.x > x2) {
+ x2 = p.x;
+ }
+ if (p.y > y2) {
+ y2 = p.y;
+ }
+ }
+ var dx = x2 - x1,
+ dy = y2 - y1;
+ if (dx > dy) {
+ y2 = y1 + dx;
+ } else {
+ x2 = x1 + dy;
+ }
+ function insert(n, p, x1, y1, x2, y2) {
+ if (isNaN(p.x) || isNaN(p.y)) {
+ return;
+ }
+ if (n.leaf) {
+ var v = n.point;
+ if (v) {
+ if (Math.abs(v.x - p.x) + Math.abs(v.y - p.y) < 0.01) {
+ insertChild(n, p, x1, y1, x2, y2);
+ } else {
+ n.point = null;
+ insertChild(n, v, x1, y1, x2, y2);
+ insertChild(n, p, x1, y1, x2, y2);
+ }
+ } else {
+ n.point = p;
+ }
+ } else {
+ insertChild(n, p, x1, y1, x2, y2);
+ }
+ }
+ function insertChild(n, p, x1, y1, x2, y2) {
+ var sx = (x1 + x2) * 0.5,
+ sy = (y1 + y2) * 0.5,
+ right = p.x >= sx,
+ bottom = p.y >= sy,
+ i = (bottom << 1) + right;
+ n.leaf = false;
+ n = n.nodes[i] || (n.nodes[i] = { leaf: true, nodes: [], point: null });
+ if (right) {
+ x1 = sx;
+ } else {
+ x2 = sx;
+ }
+ if (bottom) {
+ y1 = sy;
+ } else {
+ y2 = sy;
+ }
+ insert(n, p, x1, y1, x2, y2);
+ }
+ function quadtreeVisit(f, node, x1, y1, x2, y2) {
+ if (!f(node, x1, y1, x2, y2)) {
+ var sx = (x1 + x2) * 0.5,
+ sy = (y1 + y2) * 0.5,
+ children = node.nodes;
+ if (children[0]) {
+ quadtreeVisit(f, children[0], x1, y1, sx, sy);
+ }
+ if (children[1]) {
+ quadtreeVisit(f, children[1], sx, y1, x2, sy);
+ }
+ if (children[2]) {
+ quadtreeVisit(f, children[2], x1, sy, sx, y2);
+ }
+ if (children[3]) {
+ quadtreeVisit(f, children[3], sx, sy, x2, y2);
+ }
+ }
+ }
+ var root = { leaf: true, nodes: [], point: null };
+ root.add = function (p) {
+ insert(root, p, x1, y1, x2, y2);
+ };
+ root.visit = function (f) {
+ quadtreeVisit(f, root, x1, y1, x2, y2);
+ };
+ points.forEach(root.add);
+ return root;
+ };
+ var TypeGatherLayout = function (nodes, links) {
+ this.nodes = nodes;
+ this.links = links;
+ this.SPEED_DIVISOR = 800;
+ this.AREA_MULTIPLICATOR = 100000;
+ this.area = 2;
+ this.speed = 5;
+ this.inited = false;
+ };
+ TypeGatherLayout.prototype.getConfig = function () {
+ var self = this;
+ return [
+ { label: "间距", area: self.area },
+ { label: "移动速度", speed: self.speed },
+ ];
+ };
+ TypeGatherLayout.prototype.resetConfig = function (layoutConfig) {
+ this.initAlgo();
+ if (layoutConfig) {
+ this.area = Number(layoutConfig["area"]) || 2;
+ this.speed = Number(layoutConfig["speed"]) || 5;
+ }
+ };
+ TypeGatherLayout.prototype.initAlgo = function () {
+ var self = this;
+ this.area = 200;
+ this.speed = 5;
+ this.nodes.forEach(function (n) {
+ n.layoutData = self.newLayoutData();
+ });
+ this.maxDisplace = Math.sqrt(self.AREA_MULTIPLICATOR * self.area) / 10;
+ this.k = Math.sqrt(
+ (self.AREA_MULTIPLICATOR * self.area) / (1 + self.nodes.length),
+ );
+ this.inited = true;
+ };
+ TypeGatherLayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ TypeGatherLayout.prototype.goAlgo = function () {
+ var self = this;
+ self.repulsiveForce();
+ self.attractiveForce();
+ self.sameTypeAttractive();
+ self.resetNodePosition();
+ };
+ TypeGatherLayout.prototype.repulsiveForce = function () {
+ var self = this;
+ self.nodes.forEach(function (N1, i) {
+ self.nodes.forEach(function (N2, j) {
+ if (i != j) {
+ var xDist = N1.x - N2.x;
+ var yDist = N1.y - N2.y;
+ var dist = Math.sqrt(xDist * xDist + yDist * yDist);
+ if (dist > 1.0) {
+ var repulsiveF = (self.k * self.k) / dist;
+ var layoutData = N1.layoutData;
+ layoutData.dx += (xDist / dist) * repulsiveF * 0.01;
+ layoutData.dy += (yDist / dist) * repulsiveF * 0.01;
+ }
+ }
+ });
+ });
+ };
+ TypeGatherLayout.prototype.attractiveForce = function () {
+ var self = this;
+ self.links.forEach(function (E) {
+ var Nf = E.source;
+ var Nt = E.target;
+ var xDist = Nf.x - Nt.x;
+ var yDist = Nf.y - Nt.y;
+ var dist = Math.sqrt(xDist * xDist + yDist * yDist);
+ var attractiveF = (dist * dist) / self.k;
+ if (dist > 1.0) {
+ var sourceLayoutData = Nf.layoutData;
+ var targetLayoutData = Nt.layoutData;
+ sourceLayoutData.dx -= (xDist / dist) * attractiveF;
+ sourceLayoutData.dy -= (yDist / dist) * attractiveF;
+ targetLayoutData.dx += (xDist / dist) * attractiveF;
+ targetLayoutData.dy += (yDist / dist) * attractiveF;
+ }
+ });
+ };
+ TypeGatherLayout.prototype.sameTypeAttractive = function () {
+ var self = this;
+ self.nodes.forEach(function (N1, i) {
+ self.nodes.forEach(function (N2, j) {
+ if (i != j && N1.cluster == N2.cluster) {
+ var xDist = N1.x - N2.x;
+ var yDist = N1.y - N2.y;
+ var dist = Math.sqrt(xDist * xDist + yDist * yDist);
+ if (dist > 0) {
+ var attractiveF = (dist * dist) / self.k;
+ var sourceLayoutData = N1.layoutData;
+ var targetLayoutData = N2.layoutData;
+ sourceLayoutData.dx -= (xDist / dist) * attractiveF;
+ sourceLayoutData.dy -= (yDist / dist) * attractiveF;
+ targetLayoutData.dx += (xDist / dist) * attractiveF;
+ targetLayoutData.dy += (yDist / dist) * attractiveF;
+ }
+ }
+ });
+ });
+ };
+ TypeGatherLayout.prototype.resetNodePosition = function () {
+ var self = this;
+ self.nodes.forEach(function (node) {
+ node.layoutData.dx *= self.speed / self.SPEED_DIVISOR;
+ node.layoutData.dy *= self.speed / self.SPEED_DIVISOR;
+ var layoutData = node.layoutData;
+ var xDist = layoutData.dx;
+ var yDist = layoutData.dy;
+ var dist = Math.sqrt(
+ layoutData.dx * layoutData.dx + layoutData.dy * layoutData.dy,
+ );
+ if (dist > 0 && !node.fixed) {
+ var limitedDist = Math.min(
+ self.maxDisplace * (self.speed / self.SPEED_DIVISOR),
+ dist,
+ );
+ node.x = node.x + (xDist / dist) * limitedDist;
+ node.y = node.y + (yDist / dist) * limitedDist;
+ }
+ });
+ };
+ TypeGatherLayout.prototype.newLayoutData = function () {
+ var layoutData = { dx: 0.0, dy: 0.0 };
+ return layoutData;
+ };
+ var SpiralLayout = function SpiralLayout(nodes) {
+ this.nodes = nodes;
+ this.radius = NaN;
+ this.spacing = 10;
+ this.clockwise = true;
+ this.center = [100, 100];
+ };
+ SpiralLayout.prototype.getConfig = function () {
+ var self = this;
+ return [{ label: "间距", spacing: 10 }];
+ };
+ SpiralLayout.prototype.resetConfig = function (layoutConfig) {
+ if (layoutConfig) {
+ this.spacing = Number(layoutConfig["spacing"]) || 10;
+ this.center = layoutConfig["center"] || [100, 100];
+ }
+ this.initAlgo();
+ };
+ SpiralLayout.prototype.initAlgo = function () {
+ var self = this;
+ var originx = self.center[0];
+ var originy = self.center[1];
+ var nodes = self.nodes.sort(function (n1, n2) {
+ var x = (n1.inLinks || []).length + (n1.outLinks || []).length;
+ var y = (n2.inLinks || []).length + (n2.outLinks || []).length;
+ if (x > y) {
+ return -1;
+ } else if (x < y) {
+ return 1;
+ } else {
+ return 0;
+ }
+ });
+ var root = nodes[0];
+ var space = self.spacing;
+ var cw = self.clockwise ? 1 : -1;
+ var rad = self.radius;
+ if (rad <= 0 || isNaN(rad) || !isFinite(rad)) {
+ rad = this.diameter(root);
+ }
+ var dia = this.diameter(root);
+ var angle = cw * Math.PI;
+ root.x = originx;
+ root.y = originy;
+ var nodeLength = nodes.length;
+ for (var i = 1; i < nodeLength; i++) {
+ var cos = Math.cos(angle);
+ var sin = Math.sin(angle);
+ var x = rad * (cos + angle * sin);
+ var y = rad * (sin - angle * cos);
+ var vert = nodes[i];
+ vert.x = x + originx;
+ vert.y = y + originy;
+ var nextvert = nodes[i + 1];
+ var dia = self.diameter(vert) / 2 + self.diameter(nextvert) / 2;
+ angle += cw * Math.atan((dia + space) / Math.sqrt(x * x + y * y));
+ }
+ };
+ SpiralLayout.prototype.diameter = function (v) {
+ if (!v) {
+ return 0;
+ }
+ return Math.sqrt(v.radius * v.radius + v.radius * v.radius);
+ };
+ SpiralLayout.prototype.runLayout = function () {
+ if (this.inited) {
+ this.goAlgo();
+ }
+ };
+ SpiralLayout.prototype.goAlgo = function () {};
+ var layoutFac = function (_graph, config) {
+ console.log(_graph);
+ if (!_graph || _graph == null) {
+ return;
+ }
+ this.config = config || {};
+ this.graph = { nodes: _graph.nodes || [], links: _graph.links || [] };
+ };
+ layoutFac.prototype.createLayout = function (layoutType) {
+ if (layoutType == null) {
+ return null;
+ }
+ return this.getLayout(layoutType);
+ };
+ layoutFac.prototype.getLayout = function (layoutType, configs) {
+ var _self = this;
+ var nodes = _self.graph.nodes || [];
+ var links = _self.graph.links || [];
+ console.log(nodes);
+ var layout;
+ switch (layoutType) {
+ case "concentric":
+ layout = new ConcentricLayout(nodes, links);
+ break;
+ case "singleCirlce":
+ layout = new CircleLayout(nodes, links);
+ break;
+ case "dualCirlce":
+ layout = new DualCircleLayout(nodes, links);
+ break;
+ case "layerCircle":
+ layout = new LayerLayout(nodes, links);
+ break;
+ case "fr":
+ layout = new FRlayout(nodes, links);
+ break;
+ case "fastFR":
+ layout = new ForceD3Layout(nodes, links);
+ break;
+ case "frDirect":
+ layout = new ForceDirected(nodes, links);
+ break;
+ case "fruchtermanReingold":
+ layout = new FruchtermanReingoldLayout(nodes, links);
+ break;
+ case "spring2":
+ layout = new SpringLayout2(nodes, links);
+ break;
+ case "kk":
+ layout = new KKLayout(nodes, links);
+ break;
+ case "arf":
+ layout = new ARFLayout(nodes, links);
+ break;
+ case "tree":
+ layout = new TreeLayout(nodes, links);
+ break;
+ case "radiatree":
+ layout = new RadiaTreeLayout(nodes, links);
+ break;
+ case "balloon":
+ layout = new BalloonLayout(nodes, links);
+ break;
+ case "noverlap":
+ layout = new AvoidOverlapLayout(nodes, links);
+ break;
+ case "sphere":
+ layout = new SphereLayout(nodes, links);
+ break;
+ case "layered":
+ layout = new LayeredLayout(nodes, links);
+ break;
+ case "topoCircle":
+ layout = new TopoTreeLayout(nodes, links);
+ break;
+ case "hubsize":
+ layout = new HierarchicalLayout(nodes, links);
+ break;
+ case "hive":
+ layout = new HiveLayout(nodes, links);
+ break;
+ case "scale":
+ layout = new ScaleLayout(nodes, null, 1);
+ break;
+ case "rotate":
+ layout = new RotateLayout(nodes, null, 0);
+ break;
+ case "grid":
+ layout = new GirdLayout(nodes);
+ break;
+ case "gather":
+ layout = new TypeGatherLayout(nodes, links);
+ break;
+ case "spiral":
+ layout = new SpiralLayout(nodes);
+ break;
+ default:
+ break;
+ }
+ if (!layout) {
+ return null;
+ }
+ return layout;
+ };
+ var LayoutFactory = layoutFac;
+ if (typeof module !== "undefined" && typeof exports === "object") {
+ module.exports = LayoutFactory;
+ } else if (typeof define === "function" && (define.amd || define.cmd)) {
+ define(function () {
+ return LayoutFactory;
+ });
+ } else {
+ this.LayoutFactory = LayoutFactory;
+ }
+}).call(this || (typeof window !== "undefined" ? window : global));
diff --git a/kcui/src/assets/js/graphvis.min.20241008.js b/kcui/src/assets/js/graphvis.min.20241008.js
new file mode 100644
index 0000000..35dc98a
--- /dev/null
+++ b/kcui/src/assets/js/graphvis.min.20241008.js
@@ -0,0 +1,9648 @@
+/* eslint-disable */
+
+(function () {
+ const DGraph = {
+ version: "4.5.1",
+ Group_zIndex: 1,
+ Link_zIndex: 2,
+ Node_zIndex: 3,
+ SceneMode: { normal: "normal", drag: "drag", select: "select" },
+ Element: function () {
+ (this.initialize = function () {
+ this.elementType = "element";
+ this.serializedProperties = ["elementType"];
+ this.propertiesStack = [];
+ }),
+ (this.removeHandler = function () {}),
+ (this.save = function () {
+ var self = this;
+ var newObj = {};
+ self.serializedProperties.forEach(function (properties) {
+ newObj[properties] = self[properties];
+ });
+ self.propertiesStack.push(newObj);
+ }),
+ (this.restore = function () {
+ var self = this;
+ if (
+ null != self.propertiesStack &&
+ 0 != self.propertiesStack.length
+ ) {
+ var stack = self.propertiesStack.pop();
+ self.serializedProperties.forEach(function (attr) {
+ self[attr] = stack[attr];
+ });
+ }
+ });
+ },
+ };
+ !(function (DGraph) {
+ function MessageBus(name) {
+ var self = this;
+ this.name = name;
+ this.messageMap = {};
+ this.messageCount = 0;
+ (this.subscribe = function (name, caller) {
+ var message = self.messageMap[name];
+ null == message && (self.messageMap[name] = []),
+ self.messageMap[name].push(caller),
+ self.messageCount++;
+ }),
+ (this.unsubscribe = function (name) {
+ var message = self.messageMap[name];
+ null != message &&
+ ((self.messageMap[name] = null),
+ delete self.messageMap[name],
+ self.messageCount--);
+ }),
+ (this.publish = function (name, caller, d) {
+ var message = self.messageMap[name];
+ if (null != message) {
+ for (var i = 0; i < message.length; i++) {
+ d
+ ? !(function (event, args) {
+ setTimeout(function () {
+ event(args);
+ }, 10);
+ })(message[i], caller)
+ : message[i](caller);
+ }
+ }
+ });
+ }
+ function getEventPosition(event) {
+ var pos = null;
+ if (!event.pageX) {
+ pos = cloneEvent(event);
+ pos.pageX =
+ event.clientX + document.body.scrollLeft - document.body.clientLeft;
+ pos.pageY =
+ event.clientY + document.body.scrollTop - document.body.clientTop;
+ } else {
+ pos = cloneEvent(event);
+ }
+ return pos;
+ }
+ function cloneEvent(event) {
+ var _event = {};
+ for (var key in event)
+ "returnValue" != key &&
+ "keyLocation" != key &&
+ (_event[key] = event[key]);
+ return _event;
+ }
+ function clone(obj) {
+ var newObj = {};
+ for (var key in obj) newObj[key] = obj[key];
+ return newObj;
+ }
+ function removeFromArray(arr, item) {
+ for (var i = 0; i < arr.length; i++) {
+ var obj = arr[i];
+ if (obj == item || obj["id"] == item["id"]) {
+ arr.splice(i, 1);
+ break;
+ }
+ }
+ return arr;
+ }
+ function getOffsetPosition(a) {
+ if (!a) return { left: 0, top: 0 };
+ var b = 0,
+ c = 0;
+ if ("getBoundingClientRect" in document.documentElement) {
+ var d = a.getBoundingClientRect(),
+ e = a.ownerDocument,
+ f = e.body,
+ g = e.documentElement,
+ h = g.clientTop || f.clientTop || 0,
+ i = g.clientLeft || f.clientLeft || 0,
+ b =
+ d.top + (self.pageYOffset || (g && g.scrollTop) || f.scrollTop) - h,
+ c =
+ d.left +
+ (self.pageXOffset || (g && g.scrollLeft) || f.scrollLeft) -
+ i;
+ } else {
+ (b += a.offsetTop || 0), (c += a.offsetLeft || 0), (a = a.offsetParent);
+ }
+ return { left: c, top: b };
+ }
+ function getDistance(pointA, pointB, x1, y1) {
+ var dx, dy;
+ return (
+ null == x1 && null == y1
+ ? ((dx = pointB.x - pointA.x), (dy = pointB.y - pointA.y))
+ : ((dx = x1 - pointA), (dy = y1 - pointB)),
+ Math.sqrt(dx * dx + dy * dy)
+ );
+ }
+ function isPointInLine(mousePoint, startPoint, endPoint) {
+ var distance = DGraph.util.getDistance(startPoint, endPoint),
+ dis1 = DGraph.util.getDistance(startPoint, mousePoint),
+ dis2 = DGraph.util.getDistance(endPoint, mousePoint),
+ flag = Math.abs(dis1 + dis2 - distance) <= 0.5;
+ return flag;
+ }
+ function lineVir(x1, y1, x2, y2) {
+ var angle = (y2 - y1) / (x2 - x1),
+ distance = y1 - x1 * angle;
+ function bound(num) {
+ return num * angle + distance;
+ }
+ return (
+ (bound.k = angle),
+ (bound.b = distance),
+ (bound.x1 = x1),
+ (bound.x2 = x2),
+ (bound.y1 = y1),
+ (bound.y2 = y2),
+ bound
+ );
+ }
+ function inRange(cpoint, point1, point2) {
+ var distance1 = Math.abs(point1 - point2),
+ distance2 = Math.abs(point1 - cpoint),
+ distance3 = Math.abs(point2 - cpoint),
+ distance = Math.abs(distance1 - (distance2 + distance3));
+ return 0.000001 > distance ? true : false;
+ }
+ function isPointInLineSeg(pointA, pointB, viaPoint) {
+ return (
+ inRange(pointA, viaPoint.x1, viaPoint.x2) &&
+ inRange(pointB, viaPoint.y1, viaPoint.y2)
+ );
+ }
+ function intersection(lineA, lineB) {
+ if (lineA.k == lineB.k) {
+ return null;
+ }
+ var pointX, pointY;
+ if (Infinity == lineA.k || lineA.k == -Infinity) {
+ (pointX = lineA.x1), (pointY = lineB(lineA.x1));
+ } else if (Infinity == lineB.k || lineB.k == -Infinity) {
+ (pointX = lineB.x1), (pointY = lineA(lineB.x1));
+ } else {
+ (pointX = (lineB.b - lineA.b) / (lineA.k - lineB.k)),
+ (pointY = lineA(pointX));
+ }
+ if (0 == isPointInLineSeg(pointX, pointY, lineA)) {
+ return null;
+ }
+ if (0 == isPointInLineSeg(pointX, pointY, lineB)) {
+ return null;
+ }
+ return { x: pointX, y: pointY };
+ }
+ function intersectionLineBound(point, bound) {
+ var line = lineVir(bound.left, bound.top, bound.left, bound.bottom),
+ insertPoint = intersection(point, line);
+ if (null == insertPoint) {
+ line = lineVir(bound.left, bound.top, bound.right, bound.top);
+ insertPoint = intersection(point, line);
+ if (null == insertPoint) {
+ (line = lineVir(bound.right, bound.top, bound.right, bound.bottom)),
+ (insertPoint = intersection(point, line));
+ if (null == insertPoint) {
+ (line = lineVir(
+ bound.left,
+ bound.bottom,
+ bound.right,
+ bound.bottom,
+ )),
+ (insertPoint = intersection(point, line));
+ }
+ }
+ }
+ return insertPoint;
+ }
+ function pointOnCircle(x, y, radius, angle) {
+ return {
+ x: x + radius * Math.cos(angle),
+ y: y + radius * Math.sin(angle),
+ };
+ }
+ function findAngle(sx, sy, ex, ey) {
+ var tmp = Math.atan((ey - sy) / (ex - sx));
+ if (ex - sx >= 0) {
+ return tmp;
+ } else {
+ return tmp + Math.PI;
+ }
+ }
+ function containStroke(x0, y0, x1, y1, lineWidth, x, y) {
+ if (lineWidth === 0) {
+ return false;
+ }
+ let _l = lineWidth;
+ let _a = 0;
+ let _b = x0;
+ if (
+ (y > y0 + _l && y > y1 + _l) ||
+ (y < y0 - _l && y < y1 - _l) ||
+ (x > x0 + _l && x > x1 + _l) ||
+ (x < x0 - _l && x < x1 - _l)
+ ) {
+ return false;
+ }
+ if (x0 !== x1) {
+ _a = (y0 - y1) / (x0 - x1);
+ _b = (x0 * y1 - x1 * y0) / (x0 - x1);
+ } else {
+ return Math.abs(x - x0) <= _l / 2;
+ }
+ let tmp = _a * x - y + _b;
+ let _s = (tmp * tmp) / (_a * _a + 1);
+ return _s <= ((_l / 2) * _l) / 2;
+ }
+ function containBerzierStroke(
+ x0,
+ y0,
+ x1,
+ y1,
+ x2,
+ y2,
+ x3,
+ y3,
+ lineWidth,
+ x,
+ y,
+ ) {
+ if (lineWidth === 0) {
+ return false;
+ }
+ let _l = lineWidth;
+ if (
+ (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l) ||
+ (y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l) ||
+ (x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l) ||
+ (x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l)
+ ) {
+ return false;
+ }
+ let d = cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, null);
+ return d <= _l / 2;
+ }
+ function cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, out) {
+ var t;
+ var interval = 0.005;
+ var EPSILON_NUMERIC = 1e-4;
+ var d = Infinity;
+ var prev;
+ var next;
+ var d1;
+ var d2;
+ var _v0 = [],
+ _v1 = [],
+ _v2 = [];
+ _v0[0] = x;
+ _v0[1] = y;
+ for (var _t = 0; _t < 1; _t += 0.05) {
+ _v1[0] = cubicAt(x0, x1, x2, x3, _t);
+ _v1[1] = cubicAt(y0, y1, y2, y3, _t);
+ d1 = distanceSquare(_v0, _v1);
+ if (d1 < d) {
+ t = _t;
+ d = d1;
+ }
+ }
+ d = Infinity;
+ for (var i = 0; i < 32; i++) {
+ if (interval < EPSILON_NUMERIC) {
+ break;
+ }
+ prev = t - interval;
+ next = t + interval;
+ _v1[0] = cubicAt(x0, x1, x2, x3, prev);
+ _v1[1] = cubicAt(y0, y1, y2, y3, prev);
+ d1 = distanceSquare(_v1, _v0);
+ if (prev >= 0 && d1 < d) {
+ t = prev;
+ d = d1;
+ } else {
+ _v2[0] = cubicAt(x0, x1, x2, x3, next);
+ _v2[1] = cubicAt(y0, y1, y2, y3, next);
+ d2 = distanceSquare(_v2, _v0);
+ if (next <= 1 && d2 < d) {
+ t = next;
+ d = d2;
+ } else {
+ interval *= 0.5;
+ }
+ }
+ }
+ if (out) {
+ out[0] = cubicAt(x0, x1, x2, x3, t);
+ out[1] = cubicAt(y0, y1, y2, y3, t);
+ }
+ return Math.sqrt(d);
+ }
+ function containQuadraticStroke(x0, y0, x1, y1, x2, y2, lineWidth, x, y) {
+ if (lineWidth === 0) {
+ return false;
+ }
+ let _l = lineWidth;
+ if (
+ (y > y0 + _l && y > y1 + _l && y > y2 + _l) ||
+ (y < y0 - _l && y < y1 - _l && y < y2 - _l) ||
+ (x > x0 + _l && x > x1 + _l && x > x2 + _l) ||
+ (x < x0 - _l && x < x1 - _l && x < x2 - _l)
+ ) {
+ return false;
+ }
+ let d = quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, null);
+ return d <= _l / 2;
+ }
+ function quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, out) {
+ var t;
+ var interval = 0.005;
+ var EPSILON_NUMERIC = 1e-4;
+ var d = Infinity;
+ var d1 = 0;
+ var _v0 = [],
+ _v1 = [],
+ _v2 = [];
+ _v0[0] = x;
+ _v0[1] = y;
+ for (var _t = 0; _t < 1; _t += 0.05) {
+ _v1[0] = quadraticAt(x0, x1, x2, _t);
+ _v1[1] = quadraticAt(y0, y1, y2, _t);
+ d1 = distanceSquare(_v0, _v1);
+ if (d1 < d) {
+ t = _t;
+ d = d1;
+ }
+ }
+ d = Infinity;
+ for (var i = 0; i < 32; i++) {
+ if (interval < EPSILON_NUMERIC) {
+ break;
+ }
+ var prev = t - interval;
+ var next = t + interval;
+ _v1[0] = quadraticAt(x0, x1, x2, prev);
+ _v1[1] = quadraticAt(y0, y1, y2, prev);
+ d1 = distanceSquare(_v1, _v0);
+ if (prev >= 0 && d1 < d) {
+ t = prev;
+ d = d1;
+ } else {
+ _v2[0] = quadraticAt(x0, x1, x2, next);
+ _v2[1] = quadraticAt(y0, y1, y2, next);
+ var d2 = distanceSquare(_v2, _v0);
+ if (next <= 1 && d2 < d) {
+ t = next;
+ d = d2;
+ } else {
+ interval *= 0.5;
+ }
+ }
+ }
+ if (out) {
+ out[0] = quadraticAt(x0, x1, x2, t);
+ out[1] = quadraticAt(y0, y1, y2, t);
+ }
+ return Math.sqrt(d);
+ }
+ function distanceSquare(v1, v2) {
+ return (
+ (v1[0] - v2[0]) * (v1[0] - v2[0]) + (v1[1] - v2[1]) * (v1[1] - v2[1])
+ );
+ }
+ function cubicAt(p0, p1, p2, p3, t) {
+ var onet = 1 - t;
+ return (
+ onet * onet * (onet * p0 + 3 * t * p1) +
+ t * t * (t * p3 + 3 * onet * p2)
+ );
+ }
+ function quadraticAt(p0, p1, p2, t) {
+ var onet = 1 - t;
+ return onet * (onet * p0 + 2 * t * p1) + t * t * p2;
+ }
+ function near(x, y, x1, y1, radius) {
+ let distance = Math.sqrt(Math.pow(x1 - x, 2) + Math.pow(y1 - y, 2));
+ return distance <= radius;
+ }
+ function getSelfLoopControlPoints(x, y, size) {
+ return { x1: x + size * 7, y1: y, x2: x, y2: y - size * 7 };
+ }
+ function getPointOnBezierCurve(t, x1, y1, x2, y2, cx, cy, dx, dy) {
+ var B0_t = Math.pow(1 - t, 3),
+ B1_t = 3 * t * Math.pow(1 - t, 2),
+ B2_t = 3 * Math.pow(t, 2) * (1 - t),
+ B3_t = Math.pow(t, 3);
+ return {
+ x: B0_t * x1 + B1_t * cx + B2_t * dx + B3_t * x2,
+ y: B0_t * y1 + B1_t * cy + B2_t * dy + B3_t * y2,
+ };
+ }
+ function getQuadraticControlPoint(x1, y1, x2, y2, curverNum, curveness) {
+ curveness = curveness || 0.5;
+ return {
+ x: (x1 + x2) * curveness + (y2 - y1) / (curverNum || 4),
+ y: (y1 + y2) * curveness + (x1 - x2) / (curverNum || 4),
+ };
+ }
+ function getPointOnQuadraticCurve(t, x1, y1, x2, y2, xi, yi) {
+ return {
+ x: Math.pow(1 - t, 2) * x1 + 2 * (1 - t) * t * xi + Math.pow(t, 2) * x2,
+ y: Math.pow(1 - t, 2) * y1 + 2 * (1 - t) * t * yi + Math.pow(t, 2) * y2,
+ };
+ }
+ function isInPolygon(checkPoint, polygonPoints) {
+ var counter = 0;
+ var i;
+ var xinters;
+ var p1, p2;
+ var pointCount = polygonPoints.length;
+ p1 = polygonPoints[0];
+ for (i = 1; i <= pointCount; i++) {
+ p2 = polygonPoints[i % pointCount];
+ if (
+ checkPoint[0] > Math.min(p1[0], p2[0]) &&
+ checkPoint[0] <= Math.max(p1[0], p2[0])
+ ) {
+ if (checkPoint[1] <= Math.max(p1[1], p2[1])) {
+ if (p1[0] != p2[0]) {
+ xinters =
+ ((checkPoint[0] - p1[0]) * (p2[1] - p1[1])) / (p2[0] - p1[0]) +
+ p1[1];
+ if (p1[1] == p2[1] || checkPoint[1] <= xinters) {
+ counter++;
+ }
+ }
+ }
+ }
+ p1 = p2;
+ }
+ if (counter % 2 == 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ function findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
+ var t1 = 1 - t,
+ t13 = Math.pow(t1, 3),
+ t12 = Math.pow(t1, 2),
+ t2 = t * t,
+ t3 = t2 * t,
+ x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x,
+ y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y,
+ mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x),
+ my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y),
+ nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x),
+ ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y),
+ ax = t1 * p1x + t * c1x,
+ ay = t1 * p1y + t * c1y,
+ cx = t1 * c2x + t * p2x,
+ cy = t1 * c2y + t * p2y,
+ alpha = 90 - (Math.atan2(mx - nx, my - ny) * 180) / Math.PI;
+ (mx > nx || my < ny) && (alpha += 180);
+ return {
+ x: x,
+ y: y,
+ m: { x: mx, y: my },
+ n: { x: nx, y: ny },
+ start: { x: ax, y: ay },
+ end: { x: cx, y: cy },
+ alpha: alpha,
+ };
+ }
+ function calPointOnCircle(x, y, radius, percentage) {
+ var angle = percentage * 2 * Math.PI;
+ return {
+ x: x + radius * Math.cos(angle),
+ y: y - radius * Math.sin(angle),
+ };
+ }
+ function calculateAngle(sx, sy, tx, ty) {
+ var x = Math.abs(sx - tx);
+ var y = Math.abs(sy - ty);
+ var z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
+ var radina = Math.acos(y / z);
+ var angle = Math.floor(180 / (Math.PI / radina));
+ if (tx > sx && ty > sy) {
+ angle = 180 - angle;
+ }
+ if (tx == sx && ty > sy) {
+ angle = 180;
+ }
+ if (tx > sx && ty == sy) {
+ angle = 90;
+ }
+ if (tx < sx && ty > sy) {
+ angle = 180 + angle;
+ }
+ if (tx < sx && ty == sy) {
+ angle = 270;
+ }
+ if (tx < sx && ty < sy) {
+ angle = 360 - angle;
+ }
+ return angle;
+ }
+ function createWebWorker(content) {
+ const blob = new Blob([content], { type: "application/javascript" });
+ const blobURL = URL.createObjectURL(blob);
+ const worker = new Worker(blobURL);
+ return worker;
+ }
+ (requestAnimationFrame =
+ window.requestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ function (callback) {
+ setTimeout(callback, 1000 / 60);
+ }),
+ (cancelAnimationFrame =
+ window.cancelAnimationFrame ||
+ window.webkitCancelAnimationFrame ||
+ window.mozCancelAnimationFrame ||
+ window.cancelRequestAnimationFrame ||
+ window.webkitCancelRequestAnimationFrame ||
+ window.mozCancelRequestAnimationFrame ||
+ function (id) {
+ clearTimeout(id);
+ });
+ DGraph.util = {
+ getDistance: getDistance,
+ MessageBus: MessageBus,
+ isFirefox: navigator.userAgent.indexOf("Firefox") > 0,
+ isIE: !(
+ !window.attachEvent || -1 !== navigator.userAgent.indexOf("Opera")
+ ),
+ isChrome: null != navigator.userAgent.toLowerCase().match(/chrome/),
+ clone: clone,
+ isPointInLine: isPointInLine,
+ removeFromArray: removeFromArray,
+ getEventPosition: getEventPosition,
+ cloneEvent: cloneEvent,
+ getOffsetPosition: getOffsetPosition,
+ lineVir: lineVir,
+ intersection: intersection,
+ intersectionLineBound: intersectionLineBound,
+ pointOnCircle: pointOnCircle,
+ calPointOnCircle: calPointOnCircle,
+ findAngle: findAngle,
+ containStroke: containStroke,
+ containBerzierStroke: containBerzierStroke,
+ containQuadraticStroke: containQuadraticStroke,
+ near: near,
+ isInPolygon: isInPolygon,
+ findDotsAtSegment: findDotsAtSegment,
+ getSelfLoopControlPoints: getSelfLoopControlPoints,
+ getPointOnBezierCurve: getPointOnBezierCurve,
+ getQuadraticControlPoint: getQuadraticControlPoint,
+ getPointOnQuadraticCurve: getPointOnQuadraticCurve,
+ calculateAngle: calculateAngle,
+ createWebWorker: createWebWorker,
+ };
+ DGraph.imgStore = {};
+ CanvasRenderingContext2D.prototype.DGraphRoundRect = function (
+ x,
+ y,
+ width,
+ height,
+ borderRadius,
+ ) {
+ if ("undefined" == typeof borderRadius) {
+ if (width < 2 * borderRadius) {
+ borderRadius = width / 2;
+ }
+ if (height < 2 * borderRadius) {
+ borderRadius = hieght / 2;
+ }
+ this.beginPath();
+ this.rect(x, y, width, height);
+ this.closePath();
+ } else {
+ if (width < 2 * borderRadius) {
+ borderRadius = width / 2;
+ }
+ if (height < 2 * borderRadius) {
+ borderRadius = height / 2;
+ }
+ this.beginPath();
+ this.moveTo(x + borderRadius, y);
+ this.arcTo(x + width, y, x + width, y + height, borderRadius);
+ this.arcTo(x + width, y + height, x, y + height, borderRadius);
+ this.arcTo(x, y + height, x, y, borderRadius);
+ this.arcTo(x, y, x + width, y, borderRadius);
+ this.closePath();
+ }
+ };
+ CanvasRenderingContext2D.prototype.drawArrowLine = function (
+ x0,
+ y0,
+ x1,
+ y1,
+ width,
+ ) {
+ if (width === void 0) {
+ width = 3;
+ }
+ if (width < 3) width = 3;
+ var polarCoordinate2canvasCoordinate = function (x0, y0, r, radian) {
+ var x = r * Math.cos(radian);
+ var y = r * Math.sin(radian);
+ x += x0;
+ y += y0;
+ return { x: x, y: y };
+ };
+ var distance = Math.sqrt((y1 - y0) * (y1 - y0) + (x1 - x0) * (x1 - x0));
+ var radian = Math.asin(Math.abs(y1 - y0) / distance);
+ if (x0 > x1 && y1 > y0) {
+ radian = Math.PI - radian;
+ } else if (x0 > x1 && y0 > y1) {
+ radian += Math.PI;
+ } else if (x1 > x0 && y0 > y1) {
+ radian = 2 * Math.PI - radian;
+ }
+ var _a = polarCoordinate2canvasCoordinate(
+ x0,
+ y0,
+ distance - width * 2,
+ radian,
+ ),
+ x = _a.x,
+ y = _a.y;
+ var p1 = polarCoordinate2canvasCoordinate(
+ x,
+ y,
+ width,
+ radian - Math.PI * 0.5,
+ );
+ var p2 = polarCoordinate2canvasCoordinate(
+ x,
+ y,
+ width * 2,
+ radian - Math.PI * 0.5,
+ );
+ var p3 = polarCoordinate2canvasCoordinate(
+ x,
+ y,
+ width,
+ radian + Math.PI * 0.5,
+ );
+ var p4 = polarCoordinate2canvasCoordinate(
+ x,
+ y,
+ width * 2,
+ radian + Math.PI * 0.5,
+ );
+ this.moveTo(x0, y0);
+ this.lineTo(p1.x, p1.y);
+ this.lineTo(p2.x, p2.y);
+ this.lineTo(x1, y1);
+ this.lineTo(p4.x, p4.y);
+ this.lineTo(p3.x, p3.y);
+ this.closePath();
+ };
+ CanvasRenderingContext2D.prototype.arrow = function (
+ startX,
+ startY,
+ endX,
+ endY,
+ controlPoints,
+ ) {
+ var dx = endX - startX;
+ var dy = endY - startY;
+ var len = Math.sqrt(dx * dx + dy * dy);
+ var sin = dy / len;
+ var cos = dx / len;
+ var a = [];
+ a.push(0, 0);
+ for (var i = 0; i < controlPoints.length; i += 2) {
+ var x = controlPoints[i];
+ var y = controlPoints[i + 1];
+ a.push(x < 0 ? len + x : x, y);
+ }
+ a.push(len, 0);
+ for (var i = controlPoints.length; i > 0; i -= 2) {
+ var x = controlPoints[i - 2];
+ var y = controlPoints[i - 1];
+ a.push(x < 0 ? len + x : x, -y);
+ }
+ a.push(0, 0);
+ for (var i = 0; i < a.length; i += 2) {
+ var x = a[i] * cos - a[i + 1] * sin + startX;
+ var y = a[i] * sin + a[i + 1] * cos + startY;
+ if (i === 0) this.moveTo(x, y);
+ else this.lineTo(x, y);
+ }
+ };
+ })(DGraph),
+ (function (DGraph) {
+ function Thumbnail(stage, miniMapConfig) {
+ (this.padding = 0),
+ (this.visible = false),
+ (this.container = null),
+ (this.canvas = null),
+ (this.viewBox = null),
+ (this.thumbnailCtx = null),
+ (this.width = miniMapConfig.width),
+ (this.height = miniMapConfig.height);
+ this.timer = null;
+ this.sceneChilds = 0;
+ this.initialize = function () {
+ var container = document.createElement("div");
+ container.className = "thumbnail";
+ container.style.cssText = `position:absolute;width:${this.width}px;height:${this.height}px;border:1px solid#e1d2d2;background-color:transparent;overflow:hidden;user-select:none;-webkit-user-drag:none;-webkit-tap-highlight-color:rgba(0,0,0 0);`;
+ var viewportCvs = document.createElement("canvas");
+ viewportCvs.style.cssText =
+ "width:100%;height:100%;background-color:transparent;cursor:not-allowed;pointer-events:none;";
+ viewportCvs.width = this.width * stage.pixelRatio;
+ viewportCvs.height = this.height * stage.pixelRatio;
+ var miniMapContainer = miniMapConfig.container;
+ var viewContainer = document.getElementById(miniMapContainer);
+ if (viewContainer) {
+ viewContainer.appendChild(container);
+ container.style.left = 0;
+ container.style.top = 0;
+ } else {
+ stage.canvas.parentNode.style.position = "relative";
+ stage.canvas.parentNode.appendChild(container);
+ container.style.right = 0;
+ container.style.bottom = 0;
+ }
+ container.appendChild(viewportCvs);
+ var viewBox = document.createElement("div");
+ viewBox.style.cssText = `position:absolute;top:0px;left:0px;width:${this.width * stage.pixelRatio}px;height:${this.height * stage.pixelRatio}px;border:1px solid ${miniMapConfig.viewColor};background:rgba(110,110,250,0.3);cursor:not-allowed;pointer-events:none;`;
+
+ container.appendChild(viewBox);
+ this.container = container;
+ this.canvas = viewportCvs;
+ this.thumbnailCtx = viewportCvs.getContext("2d");
+ this.viewBox = viewBox;
+ this.addThumbEvents();
+ };
+ this.addThumbEvents = function () {
+ var self = this;
+ this.container.addEventListener("click", function (event) {
+ var mouse = { left: event.offsetX, top: event.offsetY };
+ var bound = stage.boundCache;
+ var scene = stage.childs[0];
+ var left = bound.left * (self.width / bound.width) + mouse.left;
+ var top = bound.top * (self.height / bound.height) + mouse.top;
+ var scaleX = stage.width / (scene.scaleX * bound.width);
+ var scaleY = stage.height / (scene.scaleY * bound.height);
+ left /= scaleX;
+ top /= scaleY;
+ var translateX = left / ((self.width / stage.width) * scene.scaleX);
+ var translateY =
+ top / ((self.height / stage.height) * scene.scaleY);
+ scene.setCenter(translateX, translateY);
+ stage.repaint();
+ });
+ };
+ this.destory = function () {
+ this.visible = false;
+ this.sceneChilds = 0;
+ clearInterval(this.timer);
+ if (this.container) {
+ this.container.removeEventListener("click", function () {}, false);
+ this.container.parentNode.removeChild(this.container);
+ this.container = null;
+ this.canvas = null;
+ this.thumbnailCtx = null;
+ }
+ };
+ this.show = function () {
+ var self = this;
+ if (!this.visible && this.container == null) {
+ this.initialize();
+ this.visible = true;
+ self.timer = setInterval(function () {
+ var currentChildCount = stage.childs[0].childs.length;
+ if (
+ currentChildCount == 0 ||
+ self.sceneChilds != currentChildCount
+ ) {
+ self.update();
+ self.paint();
+ }
+ self.sceneChilds = currentChildCount;
+ }, 1000);
+ }
+ };
+ (this.update = function () {
+ var bound = stage.getBound();
+ if (bound == null || bound.width < 0) {
+ return null;
+ }
+ var scene = stage.childs[0];
+ var width = this.width * stage.pixelRatio;
+ var height = this.height * stage.pixelRatio;
+ var scale = Math.min(width / bound.width, height / bound.height);
+ var ctx = this.thumbnailCtx;
+ ctx.save(),
+ ctx.clearRect(0, 0, width, height),
+ scene.save(),
+ scene.centerAndZoom(scale, scale, ctx),
+ scene.paintNodes(ctx);
+ scene.restore();
+ ctx.restore();
+ }),
+ (this.paint = function () {
+ if (!this.visible) {
+ return;
+ }
+ var bound = stage.boundCache;
+ if (bound == null) {
+ return;
+ }
+ var scene = stage.childs[0];
+ var translate = scene.getOffsetTranslate();
+ var left =
+ translate.translateX *
+ (this.width / stage.width) *
+ scene.scaleX,
+ top =
+ translate.translateY *
+ (this.height / stage.height) *
+ scene.scaleY,
+ scaleX = stage.width / (scene.scaleX * bound.width),
+ scaleY = stage.height / (scene.scaleY * bound.height);
+ (left *= scaleX), (top *= scaleY);
+ left += bound.left * (this.width / bound.width);
+ top += bound.top * (this.height / bound.height);
+ var rectWidth = Math.round(this.width * scaleX);
+ var rectHeight = Math.round(this.height * scaleY);
+ left = Math.round(left);
+ top = Math.round(top);
+ this.viewBox.style.width = `${rectWidth}px`;
+ this.viewBox.style.height = `${rectHeight}px`;
+ this.viewBox.style.left = `${-left}px`;
+ this.viewBox.style.top = `${-top}px`;
+ });
+ }
+ function Stage(container, miniMapConfig) {
+ var self = this;
+ self.canvasElements = new Map();
+ self.canvasContexts = new Map();
+ self.container = container;
+ let viewCanvas = createCanvas("elements");
+ let mouseCanvas = createCanvas("mouse");
+ self.offCanvas = document.createElement("canvas");
+ self.canvas = mouseCanvas;
+ self.viewGraphics = viewCanvas.getContext("2d");
+ self.graphics = self.offCanvas.getContext("2d");
+ self.mouseGraphics = mouseCanvas.getContext("2d");
+ self.pixelRatio = getPixelRatio(viewCanvas);
+ setCanvasSize();
+ mouseCanvas.oncontextmenu = function (e) {
+ if (e.button == 2) {
+ e.preventDefault();
+ return false;
+ }
+ };
+ function mouseEvent(event) {
+ var mouse = DGraph.util.getEventPosition(event),
+ offset = DGraph.util.getOffsetPosition(self.canvas);
+ return (
+ (mouse.offsetLeft = mouse.pageX - offset.left),
+ (mouse.offsetTop = mouse.pageY - offset.top),
+ (mouse.x = mouse.offsetLeft * self.pixelRatio),
+ (mouse.y = mouse.offsetTop * self.pixelRatio),
+ (mouse.target = null),
+ mouse
+ );
+ }
+ function createCanvas(canvasId) {
+ const canvas = document.createElement("canvas");
+ canvas.setAttribute("class", `graphvis-${canvasId}`);
+ canvas.style.position = "absolute";
+ const contextOptions = {
+ preserveDrawingBuffer: false,
+ antialias: false,
+ };
+ self.canvasElements.set(canvasId, canvas);
+ self.canvasContexts.set(
+ canvasId,
+ canvas.getContext("2d", contextOptions),
+ );
+ self.container.appendChild(canvas);
+ return canvas;
+ }
+ function setCanvasSize() {
+ var width = self.container.offsetWidth || 200;
+ var height = self.container.offsetHeight || 100;
+ self.canvasElements.forEach((_canvas, _canvasId) => {
+ _canvas.style.width = width + "px";
+ _canvas.style.height = height + "px";
+ _canvas.width = Math.round(width * self.pixelRatio);
+ _canvas.height = Math.round(height * self.pixelRatio);
+ });
+ self.offCanvas.width = Math.round(width * self.pixelRatio);
+ self.offCanvas.height = Math.round(height * self.pixelRatio);
+ }
+ function getPixelRatio(canvas) {
+ let ctx = canvas.getContext("2d");
+ if (ctx === undefined) {
+ return;
+ }
+ var numerator = 1;
+ if (typeof window !== "undefined") {
+ numerator = window.devicePixelRatio || 1.0;
+ }
+ var denominator =
+ ctx.webkitBackingStorePixelRatio ||
+ ctx.mozBackingStorePixelRatio ||
+ ctx.msBackingStorePixelRatio ||
+ ctx.oBackingStorePixelRatio ||
+ ctx.backingStorePixelRatio ||
+ 1.0;
+ return numerator / denominator;
+ }
+ function mouseover(event) {
+ document.onselectstart = function () {
+ return false;
+ };
+ var _mouseEvent = mouseEvent(event);
+ self.dispatchEventToScenes("mouseover", _mouseEvent);
+ self.dispatchEvent("mouseover", _mouseEvent);
+ }
+ function mouseout(event) {
+ self.needRepaint = false;
+ document.onselectstart = function () {
+ return true;
+ };
+ var _mouseEvent = mouseEvent(event);
+ self.dispatchEventToScenes("mouseout", _mouseEvent);
+ self.dispatchEvent("mouseout", _mouseEvent);
+ }
+ function mousedown(event) {
+ self.mouseDown = true;
+ var _mouseEvent = mouseEvent(event);
+ self.mouseDownX = _mouseEvent.x;
+ self.mouseDownY = _mouseEvent.y;
+ self.dispatchEventToScenes("mousedown", _mouseEvent);
+ self.dispatchEvent("mousedown", _mouseEvent);
+ }
+ function mouseup(event) {
+ self.mouseDown = false;
+ if (self.dragging) {
+ self.dragEndMouseUp = true;
+ setTimeout(function () {
+ self.dragEndMouseUp = false;
+ self.dragging = false;
+ self.paint();
+ }, 200);
+ }
+ var _mouseEvent = mouseEvent(event);
+ self.dispatchEventToScenes("mouseup", _mouseEvent);
+ self.dispatchEvent("mouseup", _mouseEvent);
+ self.needRepaint = false;
+ self.clearSelectArea();
+ self.thumbnail.visible && self.thumbnail.update();
+ }
+ function mousemove(event) {
+ var _mouseEvent = mouseEvent(event);
+ if (self.mouseDown && (1 == event.buttons || 0 == event.buttons)) {
+ (_mouseEvent.dx = _mouseEvent.x - self.mouseDownX),
+ (_mouseEvent.dy = _mouseEvent.y - self.mouseDownY);
+ if (
+ Math.sqrt(
+ _mouseEvent.dx * _mouseEvent.dx +
+ _mouseEvent.dy * _mouseEvent.dy,
+ ) > 2
+ ) {
+ self.dragging = true;
+ self.dispatchEventToScenes("mousedrag", _mouseEvent);
+ self.dispatchEvent("mousedrag", _mouseEvent);
+ }
+ } else {
+ if (!self.staticMode) {
+ self.dispatchEventToScenes("mousemove", _mouseEvent);
+ self.dispatchEvent("mousemove", _mouseEvent);
+ }
+ }
+ }
+ function click(event) {
+ event.preventDefault();
+ if (self.dragEndMouseUp) {
+ return false;
+ }
+ clearTimeout(self.clickTimer);
+ self.clickTimer = setTimeout(function () {
+ var _mouseEvent = mouseEvent(event);
+ self.dispatchEventToScenes("click", _mouseEvent);
+ self.dispatchEvent("click", _mouseEvent);
+ }, 200);
+ }
+ function dblclick(event) {
+ event.preventDefault();
+ clearTimeout(self.clickTimer);
+ var _mouseEvent = mouseEvent(event);
+ self.dispatchEventToScenes("dbclick", _mouseEvent);
+ self.dispatchEvent("dbclick", _mouseEvent);
+ }
+ function mousewheel(event) {
+ if (!self.wheelZoom) {
+ return;
+ }
+ self.needRepaint = true;
+ self.wheeling = self.smoothWheelMode;
+ var wheelDelta =
+ null == event.wheelDelta ? event.detail : event.wheelDelta;
+ if (wheelDelta > 0) {
+ self.zoomOut(self.wheelZoom);
+ }
+ else {
+ self.zoomIn(self.wheelZoom);
+ }
+ if (event.preventDefault) {
+ event.preventDefault();
+ } else {
+ window.event, (event.returnValue = false);
+ }
+ setTimeout(function () {
+ self.wheeling = false;
+ self.needRepaint = false;
+ self.paint();
+ }, 300);
+ }
+ function touchmove(event) {
+ event.preventDefault();
+ if (self.istouch) {
+ if (event.touches && event.touches.length < 2) {
+ mousemove(touchEventToMouseEvent(event, "mousemove"));
+ } else {
+ event.preventDefault();
+ const touches = event.touches;
+ var now = touches;
+ var start = self.touchStart;
+ if (
+ getDistance(now[0], now[1]) < getDistance(start[0], start[1])
+ ) {
+ self.zoomIn(0.95);
+ } else if (
+ getDistance(now[0], now[1]) > getDistance(start[0], start[1])
+ ) {
+ self.zoomOut(0.95);
+ }
+ self.touchStart = now;
+ }
+ } else {
+ mousemove(touchEventToMouseEvent(event, "mousemove"));
+ }
+ function getDistance(p1, p2) {
+ var x = p2.pageX - p1.pageX,
+ y = p2.pageY - p1.pageY;
+ return Math.sqrt(x * x + y * y);
+ }
+ }
+ function touchstart(event) {
+ self.istouch = true;
+ if (event.touches && event.touches.length < 2) {
+ mousedown(touchEventToMouseEvent(event, "mousedown"));
+ } else {
+ const touches = event.touches;
+ if (touches.length >= 2) {
+ self.touchStart = touches;
+ }
+ }
+ }
+ function touchend(event) {
+ if (self.istouch) {
+ self.istouch = false;
+ self.touchStart = null;
+ mouseup(touchEventToMouseEvent(event, "mousedown"));
+ }
+ }
+ function touchEventToMouseEvent(event, eventType) {
+ if (!event.changedTouches || event.changedTouches.length != 1) {
+ return false;
+ }
+ var te = event.changedTouches[0];
+ var clientX = te.clientX,
+ clientY = te.clientY,
+ screenX = te.screenX,
+ screenY = te.screenY;
+ var simEvent = new MouseEvent(eventType, {
+ clientX: clientX,
+ clientY: clientY,
+ screenX: screenX,
+ screenY: screenY,
+ button: 0,
+ buttons: 0,
+ });
+ return simEvent;
+ }
+ function initEvents(cavs) {
+ DGraph.util.isIE || !window.addEventListener
+ ? ((cavs.onmouseout = mouseout),
+ (cavs.onmouseover = mouseover),
+ (cavs.onmousedown = mousedown),
+ (cavs.onmouseup = mouseup),
+ (cavs.onmousemove = mousemove),
+ (cavs.onclick = click),
+ (cavs.ondblclick = dblclick),
+ (cavs.onmousewheel = mousewheel),
+ (cavs.touchstart = touchstart),
+ (cavs.touchmove = touchmove),
+ (cavs.touchend = touchend))
+ : (cavs.addEventListener("mouseout", mouseout),
+ cavs.addEventListener("mouseover", mouseover),
+ cavs.addEventListener("mousedown", mousedown),
+ cavs.addEventListener("mouseup", mouseup),
+ cavs.addEventListener("mousemove", mousemove),
+ cavs.addEventListener("click", click),
+ cavs.addEventListener("dblclick", dblclick),
+ cavs.addEventListener("touchstart", touchstart),
+ cavs.addEventListener("touchmove", touchmove),
+ cavs.addEventListener("touchend", touchend),
+ DGraph.util.isFirefox
+ ? cavs.addEventListener("DOMMouseScroll", mousewheel)
+ : cavs.addEventListener("mousewheel", mousewheel));
+ window.addEventListener("resize", function (event) {
+ self.resize();
+ });
+ window.addEventListener(
+ "keydown",
+ function (event) {
+ self.dispatchEventToScenes(
+ "keydown",
+ DGraph.util.cloneEvent(event),
+ false,
+ );
+ },
+ true,
+ );
+ window.addEventListener(
+ "keyup",
+ function (event) {
+ self.dispatchEventToScenes(
+ "keyup",
+ DGraph.util.cloneEvent(event),
+ false,
+ );
+ },
+ true,
+ );
+ }
+ (this.initialize = function (canvas) {
+ (this.childs = []),
+ (this.fps = -50),
+ (this.messageBus = new DGraph.util.MessageBus()),
+ (this.wheelZoom = null),
+ (this.mouseDownX = 0),
+ (this.mouseDownY = 0),
+ (this.mouseDown = false),
+ (this.needRepaint = false),
+ (this.istouch = false),
+ (this.touchStart = null),
+ (this.wheeling = false);
+ this.dragging = false;
+ this.dragEndMouseUp = false;
+ this.clickTimer = null;
+ this.openDragHideEffect = false;
+ this.smoothWheelMode = true;
+ this.staticMode = false;
+ this.requestAnimateId = null;
+ this.loadingAnimateId = null;
+ this.boundCache = null;
+ this.showDetailScale = 0.5;
+ this.thumbnail = new Thumbnail(this, miniMapConfig);
+ initEvents(canvas);
+ (this.resize = function () {
+ var nowWidth = this.container.offsetWidth;
+ var nowHeight = this.container.offsetHeight;
+ if (nowWidth == 0 || nowHeight == 0) {
+ return false;
+ }
+ setCanvasSize();
+ this.paint();
+ }),
+ (this.dispatchEventToScenes = function (
+ eventName,
+ mouse,
+ _needRepaint = true,
+ ) {
+ this.needRepaint = _needRepaint;
+ this.childs.forEach(function (item) {
+ if (item.visible == true) {
+ var event = item[eventName + "Handler"];
+ if (null == event) return null;
+ event.call(item, mouse);
+ }
+ });
+ }),
+ (this.add = function (sence) {
+ for (var i = 0; i < this.childs.length; i++)
+ if (this.childs[i] === sence) return;
+ sence.addTo(this), this.childs.push(sence);
+ }),
+ (this.remove = function (sence) {
+ if (null == sence) return null;
+ for (var i = 0; i < this.childs.length; i++)
+ if (this.childs[i] === sence)
+ return (
+ (sence.stage = null),
+ (this.childs = DGraph.util.removeFromArray(
+ this.childs,
+ this.childs[i],
+ )),
+ this
+ );
+ return this;
+ }),
+ (this.clear = function () {
+ this.childs = [];
+ }),
+ (this.addEventListener = function (eventName, eventFunction) {
+ var self = this,
+ fn = function (event) {
+ eventFunction.call(self, event);
+ };
+ return this.messageBus.subscribe(eventName, fn), this;
+ }),
+ (this.removeEventListener = function (eventName) {
+ this.messageBus.unsubscribe(eventName);
+ }),
+ (this.removeAllEventListener = function () {
+ this.messageBus = new DGraph.util.MessageBus();
+ }),
+ (this.dispatchEvent = function (eventName, event) {
+ return this.messageBus.publish(eventName, event), this;
+ });
+ }),
+ this.initialize(self.canvas);
+ var eventNames = [
+ "click",
+ "dbclick",
+ "mousedown",
+ "mouseup",
+ "mouseover",
+ "mouseout",
+ "mousemove",
+ "mousedrag",
+ "mousewheel",
+ "keydown",
+ "keyup",
+ ];
+ eventNames.forEach(function (eventName) {
+ self[eventName] = function (event) {
+ null != event
+ ? this.addEventListener(eventName, event)
+ : this.dispatchEvent(eventName);
+ };
+ });
+ (this.getPagePosition = function (x, y) {
+ var self = this;
+ if (!this.childs || this.childs.length == 0) {
+ return { pageX: 0, pageY: 0 };
+ }
+ var secne = this.childs && this.childs[0];
+ var secneOffset = secne.getOffsetTranslate();
+ var offset = DGraph.util.getOffsetPosition(self.canvas);
+ var offsetLeft =
+ ((x + secneOffset.translateX) * secne.scaleX) / self.pixelRatio;
+ var offsetTop =
+ ((y + secneOffset.translateY) * secne.scaleY) / self.pixelRatio;
+ return {
+ pageX: offsetLeft + offset.left,
+ pageY: offsetTop + offset.top,
+ };
+ }),
+ (this.getImageUrlData = function (config) {
+ var bound = this.getBound();
+ if (bound == null || bound.width < 0) {
+ return null;
+ }
+ var imageWidth = config.width || 8000;
+ var imageHeight = config.height || 8000;
+ var type = config.type;
+ var rectWidth = bound.width,
+ rectHeight = bound.height;
+ var paddingX = 0,
+ paddingY = 0;
+ if (
+ bound.leftNode.elementType == "node" &&
+ bound.rightNode.elementType == "node"
+ ) {
+ paddingX =
+ bound.leftNode.radius * bound.leftNode.scaleX +
+ bound.rightNode.radius * bound.rightNode.scaleX;
+ paddingY =
+ bound.topNode.radius * bound.topNode.scaleY +
+ bound.bottomNode.radius * bound.bottomNode.scaleY;
+ }
+ rectWidth += paddingX + 50;
+ rectHeight += paddingY + 50;
+ var exportCanvas = document.createElement("canvas");
+ var width = Math.min(imageWidth || 10000, rectWidth);
+ var height = Math.min(imageHeight || 10000, rectHeight);
+ exportCanvas.width = width;
+ exportCanvas.height = height;
+ var scale = Math.min(width / rectWidth, height / rectHeight);
+ if (Math.max(rectWidth, rectHeight) < 500) {
+ exportCanvas.width = Math.max(
+ Math.max(rectWidth, rectHeight),
+ 500,
+ );
+ exportCanvas.height = Math.max(
+ Math.max(rectWidth, rectHeight),
+ 500,
+ );
+ scale = 1;
+ }
+ var exportContext2d = exportCanvas.getContext("2d");
+ if (config.background) {
+ exportContext2d.save();
+ exportContext2d.fillStyle = config.background || "#fff";
+ exportContext2d.fillRect(0, 0, width, height);
+ exportContext2d.restore();
+ }
+ if (config.textWatermark) {
+ exportContext2d.save();
+ this.paintTextWatermark(exportContext2d, width, height, {
+ content: config.textWatermark.content || " ",
+ angle: config.textWatermark.angle || -30,
+ alpha: config.textWatermark.alpha || 0.1,
+ fontStyle: config.textWatermark.fontStyle || "normal",
+ fontSize: config.textWatermark.fontSize || 60,
+ fontFamliy: config.textWatermark.fontFamliy || "Arial",
+ fontColor: config.textWatermark.color || "#666",
+ });
+ exportContext2d.restore();
+ }
+ var scene = this.childs[0];
+ scene.save(),
+ scene.centerAndZoom(scale, scale, exportContext2d),
+ scene.repaint(exportContext2d, true),
+ scene.restore();
+ var imageObj = null;
+ try {
+ imageObj = exportCanvas.toDataURL("image/" + (type || "png"), 1);
+ } catch (m) {}
+ return imageObj;
+ }),
+ (this.paintTextWatermark = function (
+ context,
+ width,
+ height,
+ textWatermark,
+ ) {
+ let {
+ content,
+ alpha,
+ angle,
+ fontSize,
+ fontStyle,
+ fontFamliy,
+ fontColor,
+ } = textWatermark;
+ context.font = `${fontStyle}${fontSize}px ${fontFamliy}`;
+ var contentWidth = Math.ceil(context.measureText(content).width);
+ context.fillStyle = fontColor || "#666";
+ context.textBaseline = "middle";
+ context.textAlign = "center";
+ context.globalAlpha = alpha || 0.1;
+ var hSpace = Math.round(contentWidth * 0.6);
+ var wSpace = contentWidth + Math.round(width / 50);
+ let heightNumber = Math.ceil(height / hSpace) + 5;
+ let widthNumber = Math.ceil(width / wSpace) + 5;
+ for (let i = 0; i < heightNumber; i++) {
+ for (let w = 0; w < widthNumber; w++) {
+ context.save();
+ context.translate(w * wSpace, i * hSpace);
+ context.rotate((angle * Math.PI) / 180);
+ context.fillText(content, 0, 0);
+ context.restore();
+ }
+ }
+ context.globalAlpha = 1;
+ }),
+ (this.saveAsLocalImage = function (config) {
+ var type = config.type ? config.type : "png";
+ var imageData = this.getImageUrlData(config);
+ if (imageData != null) {
+ var fixtype = function (type) {
+ type = type.toLowerCase().replace(/jpg/i, "jpeg");
+ var r = type.match(/png|jpeg|bmp|gif/);
+ if (r) {
+ r = r[0];
+ }
+ return "image" + r;
+ };
+ imageData = imageData.replace(
+ fixtype(type),
+ "image/octet-stream",
+ );
+ let a = document.createElement("a");
+ let event = new MouseEvent("click");
+ a.download =
+ (config.fileName || "picture" + new Date().getTime()) +
+ "." +
+ type;
+ a.href = imageData;
+ a.dispatchEvent(event);
+ }
+ }),
+ (this.paint = function () {
+ if (this.childs.length > 0) {
+ this.graphics.save();
+ this.graphics.clearRect(0, 0, this.width, this.height);
+ this.childs.forEach(function (scene) {
+ scene.visible && scene.repaint(self.graphics);
+ });
+ this.graphics.restore();
+ self.viewGraphics.clearRect(0, 0, this.width, this.height);
+ self.viewGraphics.drawImage(self.offCanvas, 0, 0);
+ }
+ }),
+ (this.repaint = function () {
+ if (this.fps > 0) {
+ this.paint();
+ } else if (this.fps < 0) {
+ if (this.needRepaint) {
+ this.needRepaint = false;
+ this.paint();
+ }
+ } else {
+ this.needRepaint = false;
+ }
+ }),
+ (this.paintSelectRect = function (x, y, width, height) {
+ this.clearSelectArea();
+ this.mouseGraphics.save();
+ this.mouseGraphics.beginPath(),
+ this.mouseGraphics.rect(
+ x * this.pixelRatio,
+ y * this.pixelRatio,
+ width,
+ height,
+ ),
+ this.mouseGraphics.closePath(),
+ (this.mouseGraphics.strokeStyle = "rgba(0,225,0,0.8)"),
+ (this.mouseGraphics.fillStyle = "rgba(0,225,0,0.1)"),
+ this.mouseGraphics.fill(),
+ this.mouseGraphics.stroke(),
+ this.mouseGraphics.restore();
+ }),
+ (this.paintSelectPolygon = function (x, y, points) {
+ this.clearSelectArea();
+ this.mouseGraphics.save();
+ this.mouseGraphics.beginPath();
+ this.mouseGraphics.moveTo(x * this.pixelRatio, y * this.pixelRatio);
+ for (var i = 1; i < points.length; i++) {
+ this.mouseGraphics.lineTo(
+ points[i][0] * this.pixelRatio,
+ points[i][1] * this.pixelRatio,
+ );
+ }
+ this.mouseGraphics.closePath(),
+ (this.mouseGraphics.strokeStyle = "rgba(0,225,0,0.8)"),
+ (this.mouseGraphics.fillStyle = "rgba(0,225,0,0.1)"),
+ this.mouseGraphics.fill(),
+ this.mouseGraphics.stroke(),
+ this.mouseGraphics.restore();
+ }),
+ (this.clearSelectArea = function () {
+ this.mouseGraphics.clearRect(0, 0, this.width, this.height);
+ }),
+ (this.showLoading = function (
+ loadingText = "loading",
+ percent = 0.2,
+ ) {
+ this.clearSelectArea();
+ var ctx = this.mouseGraphics;
+ var radius = 80,
+ PI = Math.PI,
+ PI2 = PI / 2,
+ M2PI = 2 * PI;
+ ctx.save();
+ ctx.translate(this.width / 2, this.height / 2);
+ ctx.fillStyle = "rgba(240,240,240,1)";
+ ctx.strokeStyle = "rgba(200,200,200,0.8)";
+ ctx.lineWidth = 10;
+ ctx.beginPath();
+ ctx.arc(0, 0, radius, 0, Math.PI * 2, false);
+ ctx.fill();
+ ctx.stroke();
+ ctx.closePath();
+ ctx.strokeStyle = "rgba(120,120,240,0.9)";
+ ctx.lineWidth = 10;
+ ctx.lineCap = "round";
+ ctx.beginPath();
+ ctx.arc(0, 0, radius, -PI2, M2PI * percent - PI2, false);
+ ctx.stroke();
+ ctx.closePath();
+ ctx.font = "normal 16px KaiTi";
+ ctx.textAlign = "center";
+ ctx.textBaseline = "middle";
+ ctx.fillStyle = `rgba(50,50,50,1)`;
+ ctx.fillText(loadingText, 0, 0);
+ ctx.restore();
+ }),
+ (this.hideLoading = function () {
+ this.clearSelectArea();
+ }),
+ (this.zoom = function (scale) {
+ this.childs.forEach(function (child) {
+ child.visible && child.zoom(scale);
+ });
+ }),
+ (this.zoomOut = function (scale, mouseEvent) {
+ this.childs.forEach(function (child) {
+ child.visible && child.zoomOut(scale);
+ });
+ }),
+ (this.zoomIn = function (scale, mouseEvent) {
+ this.childs.forEach(function (child) {
+ child.visible && child.zoomIn(scale);
+ });
+ }),
+ (this.centerAndZoom = function () {
+ this.childs.forEach(function (child) {
+ child.visible && child.centerAndZoom();
+ });
+ }),
+ (this.setCenter = function (x, y) {
+ var self = this;
+ this.childs.forEach(function (child) {
+ var translateX = x - self.canvas.width / 2,
+ translateY = y - self.canvas.height / 2;
+ (child.translateX = -translateX),
+ (child.translateY = -translateY);
+ });
+ }),
+ (this.getBound = function () {
+ var bound = {
+ left: Number.MAX_VALUE,
+ right: Number.MIN_VALUE,
+ top: Number.MAX_VALUE,
+ bottom: Number.MIN_VALUE,
+ };
+ if (this.childs.length == 0 || this.childs[0].childs == 0) {
+ return null;
+ }
+ this.childs.forEach(function (child) {
+ var _cbound = child.getElementsBound();
+ _cbound.left < bound.left &&
+ ((bound.left = _cbound.left),
+ (bound.leftNode = _cbound.leftNode)),
+ _cbound.top < bound.top &&
+ ((bound.top = _cbound.top),
+ (bound.topNode = _cbound.topNode)),
+ _cbound.right > bound.right &&
+ ((bound.right = _cbound.right),
+ (bound.rightNode = _cbound.rightNode)),
+ _cbound.bottom > bound.bottom &&
+ ((bound.bottom = _cbound.bottom),
+ (bound.bottomNode = _cbound.bottomNode));
+ });
+ (bound.width = bound.right - bound.left),
+ (bound.height = bound.bottom - bound.top);
+ this.boundCache = bound;
+ return bound;
+ });
+ var requestFn = (() => {
+ let lastTime = 0;
+ return typeof requestAnimationFrame !== "undefined"
+ ? requestAnimationFrame
+ : function (fn) {
+ const now = Date.now();
+ const delay = Math.min(16, Math.max(0, 16 - (now - lastTime)));
+ const elapsed = (lastTime = now + delay);
+ return setTimeout(() => fn(elapsed), delay);
+ };
+ })();
+ var cancelFn =
+ typeof cancelAnimationFrame !== "undefined"
+ ? cancelAnimationFrame
+ : function (id) {
+ return clearTimeout(id);
+ };
+ function requestAnimFrame(fn, context) {
+ return requestFn((elapsed) => {
+ fn.call(context, elapsed);
+ });
+ }
+ function cancelAnimFrame(id) {
+ if (id) {
+ cancelFn(id);
+ }
+ }
+ function render() {
+ if (0 == self.fps) {
+ setTimeout(arguments.callee, 60);
+ } else {
+ cancelAnimFrame(self.requestAnimateId);
+ self.repaint();
+ self.requestAnimateId = requestAnimFrame(render);
+ }
+ }
+ render();
+ }
+ (Stage.prototype = {
+ get width() {
+ return this.canvas.width;
+ },
+ get height() {
+ return this.canvas.height;
+ },
+ set mode(mode) {
+ this.childs.forEach(function (item) {
+ item.mode = mode;
+ });
+ },
+ }),
+ (DGraph.Stage = Stage);
+ })(DGraph),
+ (function (DGraph) {
+ function Scene(_stage) {
+ var self = this;
+ (this.initialize = function () {
+ Scene.prototype.initialize.apply(this, arguments),
+ (this.messageBus = new DGraph.util.MessageBus()),
+ (this.elementType = "scene"),
+ (this.childs = []),
+ (this.zIndexMap = {}),
+ (this.zIndexArray = []),
+ (this.backgroundColor = "255,255,255"),
+ (this.visible = true),
+ (this.alpha = 0),
+ (this.scaleX = 1),
+ (this.scaleY = 1),
+ (this.scaleRange = [0.05, 10]),
+ (this.pickMode = "node-first");
+ (this.mode = DGraph.SceneMode.normal),
+ (this.translate = true),
+ (this.translateX = 0),
+ (this.translateY = 0),
+ (this.lastTranslateX = 0),
+ (this.lastTranslateY = 0),
+ (this.mouseDown = false),
+ (this.mouseDownX = null),
+ (this.mouseDownY = null),
+ (this.mouseDownEvent = null),
+ (this.dragable = true),
+ (this.areaSelect = false),
+ (this.selectBoxType = "rect"),
+ (this.operations = []),
+ (this.selectedElements = []),
+ (this.polygonPoints = null),
+ (this.polygonCoords = null),
+ (this.dragMouseIndex = 0);
+ this.displayElements = { nodes: [], links: [], groups: [] };
+ this.serializedProperties = [
+ "translateX",
+ "translateY",
+ "lastTranslatedX",
+ "lastTranslatedY",
+ "scaleX",
+ "scaleY",
+ ];
+ (this.setBackground = function (background) {
+ this.background = background;
+ }),
+ (this.addTo = function (stage) {
+ this.stage !== stage && null != stage && (this.stage = stage);
+ });
+ }),
+ this.initialize();
+ if (null != _stage) {
+ _stage.add(this);
+ this.addTo(_stage);
+ }
+ (this.show = function () {
+ this.visible = true;
+ }),
+ (this.hide = function () {
+ this.visible = false;
+ }),
+ (this.paint = function (ctx, allPaint) {
+ ctx.save();
+ ctx.scale(this.scaleX, this.scaleY);
+ if (true == this.translate) {
+ var b = this.getOffsetTranslate(ctx);
+ ctx.translate(b.translateX, b.translateY);
+ }
+ if (allPaint) {
+ this.paintAllChilds(ctx);
+ } else {
+ this.paintChilds(ctx);
+ }
+ ctx.restore(),
+ ctx.save(),
+ this.paintOperations(ctx, this.operations),
+ ctx.restore();
+ }),
+ (this.repaint = function (ctx, allPaint) {
+ this.visible && this.paint(ctx, allPaint);
+ }),
+ (this.paintBackgroud = function (ctx) {
+ if (null != this.background) {
+ ctx.drawImage(
+ this.background,
+ 0,
+ 0,
+ ctx.canvas.width,
+ ctx.canvas.height,
+ );
+ } else {
+ ctx.beginPath(),
+ (ctx.fillStyle = `rgba(${this.backgroundColor},${this.alpha})`),
+ ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height),
+ ctx.closePath();
+ }
+ }),
+ (this.getDisplayedElements = function () {
+ var self = this;
+ self.displayElements = { nodes: [], edges: [], groups: [] };
+ let smallFlag =
+ _stage.wheeling || this.scaleX <= this.scaleRange[0]
+ ? true
+ : false;
+ if (_stage.openDragHideEffect) {
+ smallFlag = _stage.dragging || smallFlag;
+ }
+ self.displayElements.groups = this.zIndexMap[DGraph.Group_zIndex];
+ var nodes = this.zIndexMap[DGraph.Node_zIndex] || [];
+ var length = nodes.length;
+ var node = null;
+ var offset = this.getOffsetTranslate();
+ var showFlag = false;
+ var showEdges = new Set();
+ for (var i = 0; i < length; i++) {
+ node = nodes[i];
+ showFlag = this.nodeInView(node, offset);
+ if (showFlag) {
+ self.displayElements.nodes.push(node);
+ if (!smallFlag) {
+ (node.outLinks || []).forEach((link) => {
+ link.visible && showEdges.add(link);
+ });
+ (node.inLinks || []).forEach((link) => {
+ link.visible && showEdges.add(link);
+ });
+ }
+ }
+ }
+ self.displayElements.edges = Array.from(showEdges);
+ return self.displayElements;
+ }),
+ (this.paintChilds = function (ctx) {
+ var self = this;
+ var displayElements = self.getDisplayedElements();
+ var smallFlag = this.scaleX <= this.scaleRange[0];
+ var selectedNodes = [],
+ selectedEdges = [];
+ (displayElements.groups || []).forEach((group) => {
+ self.paintElement(ctx, group);
+ });
+ (displayElements.edges || []).forEach((edge) => {
+ if (edge.isMouseOver || edge.selected) {
+ selectedEdges.push(edge);
+ } else {
+ self.paintElement(ctx, edge, smallFlag);
+ }
+ });
+ selectedEdges.forEach((edge) => {
+ self.paintElement(ctx, edge, smallFlag);
+ });
+ (displayElements.nodes || []).forEach((node) => {
+ if (node.isMouseOver || node.selected) {
+ selectedNodes.push(node);
+ } else {
+ self.paintElement(ctx, node, smallFlag);
+ }
+ });
+ selectedNodes.forEach((edge) => {
+ self.paintElement(ctx, edge, smallFlag);
+ });
+ }),
+ (this.paintElement = function (ctx, element, smallFlag) {
+ if (element.visible) {
+ ctx.save();
+ if (element.transformAble) {
+ var position = element.getCenterLocation();
+ ctx.translate(position.x, position.y);
+ ctx.rotate((element.rotate * Math.PI) / 180);
+ ctx.scale(element.scaleX, element.scaleY);
+ }
+ if (element.isMouseOver && !smallFlag) {
+ element.paintMouseover(ctx);
+ }
+ if (
+ element.selected ||
+ element.showSelected ||
+ element.isMouseOver
+ ) {
+ element.hideText = false;
+ } else {
+ element.hideText = false;
+ }
+ element.paint(ctx, smallFlag);
+ ctx.restore();
+ }
+ }),
+ (this.paintAllChilds = function (ctx) {
+ for (var i = 0; i < this.zIndexArray.length; i++) {
+ var d = this.zIndexArray[i],
+ e = this.zIndexMap[d];
+ for (var f = 0; f < e.length; f++) {
+ var ele = e[f];
+ if (ele.visible == true) {
+ ctx.save();
+ if (ele.transformAble) {
+ var pos = ele.getCenterLocation();
+ ctx.translate(pos.x, pos.y);
+ ctx.rotate((ele.rotate * Math.PI) / 180);
+ ctx.scale(ele.scaleX, ele.scaleY);
+ }
+ if (ele.isMouseOver) {
+ ele.paintMouseover(ctx);
+ }
+ ele.hideText = false;
+ ele.paint(ctx, false);
+ ctx.restore();
+ }
+ }
+ }
+ }),
+ (this.paintNodes = function (ctx) {
+ var nodes = this.zIndexMap[DGraph.Node_zIndex] || [];
+ if (nodes.length == 0) {
+ return false;
+ }
+ ctx.save();
+ ctx.scale(this.scaleX, this.scaleY);
+ if (true == this.translate) {
+ var offset = this.getOffsetTranslate(ctx);
+ ctx.translate(offset.translateX, offset.translateY);
+ }
+ var pos = { x: 0, y: 0 };
+ nodes.forEach(function (node) {
+ pos = node.getCenterLocation();
+ ctx.save();
+ ctx.translate(pos.x, pos.y);
+ ctx.rotate((node.rotate * Math.PI) / 180);
+ ctx.scale(node.scaleX, node.scaleY);
+ node.paint(ctx, true);
+ ctx.restore();
+ });
+ ctx.restore();
+ }),
+ (this.getOffsetTranslate = function (context) {
+ var width = this.stage.width,
+ height = this.stage.height;
+ if (context != null) {
+ width = context.canvas.width;
+ height = context.canvas.height;
+ }
+ var offsetX = width / this.scaleX / 2,
+ offsetY = height / this.scaleY / 2;
+ return {
+ translateX: this.translateX + (offsetX - offsetX * this.scaleX),
+ translateY: this.translateY + (offsetY - offsetY * this.scaleY),
+ };
+ }),
+ (this.nodeInView = function (node, offset) {
+ if (node == null || !node.visible) {
+ return false;
+ }
+ var offsetX = (node.x + offset.translateX) * this.scaleX;
+ if (offsetX > this.stage.width) {
+ return false;
+ }
+ var offsetY = (node.y + offset.translateY) * this.scaleY;
+ if (offsetY > this.stage.height) {
+ return false;
+ }
+ var width = offsetX + node.width * this.scaleX;
+ if (0 > width) {
+ return false;
+ }
+ var height = offsetY + node.height * this.scaleY;
+ if (0 > height) {
+ return false;
+ }
+ return true;
+ }),
+ (this.isVisiable = function (ele, offset) {
+ if (ele == null || !ele.visible) {
+ return false;
+ }
+ if (ele instanceof DGraph.Link) {
+ if (ele.source.visible && ele.target.visible) {
+ return true;
+ }
+ return false;
+ }
+ return this.nodeInView(ele, offset);
+ }),
+ (this.paintOperations = function (ctx, eles) {
+ for (var i = 0; i < eles.length; i++) {
+ eles[i](ctx);
+ }
+ }),
+ (this.addOperation = function (operat) {
+ return this.operations.push(operat), this;
+ }),
+ (this.clearOperations = function () {
+ return (this.operations = []), this;
+ }),
+ (this.getElementByXY = function (x, y) {
+ var elements = [];
+ var element = null;
+ var length = 0;
+ var pickSort = ["nodes", "edges", "groups"];
+ if (this.pickMode != "node-first") {
+ pickSort = ["edges", "nodes", "groups"];
+ }
+ for (var i = 0; i < pickSort.length; i++) {
+ elements = this.displayElements[pickSort[i]] || [];
+ length = elements.length;
+ for (var j = 0; j < length; j++) {
+ element = elements[j];
+ if (element.visible && element.isInBound(x, y)) {
+ return element;
+ }
+ element = null;
+ }
+ }
+ return element;
+ }),
+ (this.add = function (ele) {
+ this.childs.push(ele),
+ null == this.zIndexMap[ele.zIndex] &&
+ ((this.zIndexMap[ele.zIndex] = []),
+ this.zIndexArray.push(ele.zIndex),
+ this.zIndexArray.sort(function (zindexA, zindexB) {
+ return zindexA - zindexB;
+ })),
+ this.zIndexMap["" + ele.zIndex].push(ele);
+ }),
+ (this.remove = function (ele) {
+ this.childs = DGraph.util.removeFromArray(this.childs, ele);
+ var zIndexEles = this.zIndexMap[ele.zIndex];
+ if (zIndexEles) {
+ this.zIndexMap[ele.zIndex] = DGraph.util.removeFromArray(
+ zIndexEles,
+ ele,
+ );
+ ele.removeHandler(this);
+ }
+ }),
+ (this.clear = function () {
+ (this.childs = []),
+ (this.operations = []),
+ (this.zIndexArray = []),
+ (this.zIndexMap = {});
+ }),
+ (this.addToSelected = function (ele) {
+ if (this.selectedElements.indexOf(ele) == -1) {
+ this.selectedElements.push(ele);
+ }
+ }),
+ (this.cancleAllSelected = function (ele) {
+ for (var i = 0; i < this.selectedElements.length; i++) {
+ this.selectedElements[i].unselectedHandler(ele);
+ }
+ this.selectedElements = [];
+ }),
+ (this.notInSelectedNodes = function (ele) {
+ for (var i = 0; i < this.selectedElements.length; i++) {
+ if (ele === this.selectedElements[i]) return false;
+ }
+ return true;
+ }),
+ (this.removeFromSelected = function (ele) {
+ for (var i = 0; i < this.selectedElements.length; i++) {
+ var selEle = this.selectedElements[i];
+ if (ele === selEle) {
+ this.selectedElements = DGraph.util.removeFromArray(
+ this.selectedElements,
+ selEle,
+ );
+ }
+ }
+ }),
+ (this.toSceneEvent = function (ele) {
+ var newELe = DGraph.util.clone(ele);
+ newELe.x /= this.scaleX;
+ newELe.y /= this.scaleY;
+ if (true == this.translate) {
+ var offset = this.getOffsetTranslate();
+ newELe.x -= offset.translateX;
+ newELe.y -= offset.translateY;
+ }
+ return (
+ null != newELe.dx &&
+ ((newELe.dx /= this.scaleX), (newELe.dy /= this.scaleY)),
+ null != this.currentElement &&
+ (newELe.target = this.currentElement),
+ (newELe.scene = this),
+ newELe
+ );
+ }),
+ (this.selectElement = function (event) {
+ var self = this;
+ var selEle = self.getElementByXY(event.x, event.y);
+ if (null != selEle) {
+ event.target = selEle;
+ selEle.mousedownHander(event);
+ selEle.selectedHandler(event);
+ if (self.notInSelectedNodes(selEle)) {
+ event.ctrlKey || self.cancleAllSelected(),
+ self.addToSelected(selEle);
+ } else {
+ event.ctrlKey &&
+ (selEle.unselectedHandler(), this.removeFromSelected(selEle));
+ for (var i = 0; i < this.selectedElements.length; i++) {
+ this.selectedElements[i].selectedHandler(event);
+ }
+ }
+ } else {
+ event.ctrlKey || self.cancleAllSelected();
+ }
+ this.currentElement = selEle;
+ }),
+ (this.mousedownHandler = function (event) {
+ var evt = this.toSceneEvent(event);
+ (this.mouseDownX = evt.x),
+ (this.mouseDownY = evt.y),
+ (this.mouseDownEvent = evt);
+ if (
+ (this.mouseDown = true && this.mode == DGraph.SceneMode.normal)
+ ) {
+ this.selectElement(evt),
+ (null == this.currentElement ||
+ this.currentElement instanceof DGraph.Link) &&
+ true == this.translate &&
+ ((this.lastTranslateX = this.translateX),
+ (this.lastTranslateY = this.translateY));
+ } else {
+ if (this.mode == DGraph.SceneMode.drag && true == this.translate)
+ return (
+ (this.lastTranslateX = this.translateX),
+ (this.lastTranslateY = this.translateY)
+ );
+ this.mode == DGraph.SceneMode.select && this.selectElement(evt);
+ }
+ self.dispatchEvent("mousedown", evt);
+ }),
+ (this.mouseupHandler = function (event) {
+ self.clearOperations();
+ var evt = this.toSceneEvent(event);
+ null != this.currentElement &&
+ ((evt.target = self.currentElement),
+ this.currentElement.mouseupHandler(evt));
+ this.dispatchEvent("mouseup", evt), (this.mouseDown = false);
+ if (this.areaSelect) {
+ this.areaSelect = false;
+ this.boxSelectEndHandle();
+ }
+ }),
+ (this.dragElements = function (event) {
+ if (null != this.currentElement && this.currentElement.dragable) {
+ var e = DGraph.util.clone(event);
+ for (var i = 0; i < this.selectedElements.length; i++) {
+ var ele = this.selectedElements[i];
+ if (ele.dragable) {
+ (e.target = ele), ele.mousedragHandler(e);
+ }
+ }
+ }
+ }),
+ (this.mousedragHandler = function (event) {
+ var mouse = this.toSceneEvent(event);
+ if (this.mode == DGraph.SceneMode.normal) {
+ if (
+ null == this.currentElement ||
+ this.currentElement instanceof DGraph.Link
+ ) {
+ this.dragable &&
+ this.translate &&
+ ((this.translateX = this.lastTranslateX + mouse.dx),
+ (this.translateY = this.lastTranslateY + mouse.dy));
+ } else {
+ this.dragable && this.dragElements(mouse);
+ }
+ } else if (this.mode == DGraph.SceneMode.drag) {
+ this.dragable &&
+ this.translate &&
+ ((this.translateX = this.lastTranslateX + mouse.dx),
+ (this.translateY = this.lastTranslateY + mouse.dy));
+ } else if (this.mode == DGraph.SceneMode.select) {
+ if (null != this.currentElement) {
+ this.currentElement.dragable && this.dragElements(mouse);
+ } else {
+ this.stage.needRepaint = false;
+ this.areaSelect = true;
+ this.selectBoxType == "rect"
+ ? this.selectRectHandle(mouse)
+ : this.selectPolygonHandle(mouse);
+ }
+ } else {
+ this.dispatchEvent("mousedrag", mouse);
+ }
+ }),
+ (this.boxSelectEndHandle = function () {
+ var ele = null;
+ var pickSort = ["nodes", "groups"];
+ var nodes = [];
+ for (var i = 0; i < pickSort.length; i++) {
+ var elements = this.displayElements[pickSort[i]] || [];
+ var length = elements.length;
+ for (var j = 0; j < length; j++) {
+ ele = elements[j];
+ if (
+ DGraph.util.isInPolygon([ele.cx, ele.cy], this.polygonCoords)
+ ) {
+ ele.selectedHandler(event), this.addToSelected(ele);
+ nodes.push(ele);
+ }
+ }
+ }
+ this.boxSelectedNodes = nodes;
+ this.polygonPoints = null;
+ this.polygonCoords = null;
+ this.dragMouseIndex = 0;
+ this.stage.repaint();
+ }),
+ (this.selectPolygonHandle = function (event) {
+ var left = event.offsetLeft,
+ top = event.offsetTop;
+ this.dragMouseIndex++;
+ if (this.polygonPoints == null) {
+ this.polygonPoints = [[left, top]];
+ this.polygonCoords = [[event.x, event.y]];
+ } else {
+ if (this.dragMouseIndex % 10 == 0) {
+ this.polygonPoints.push([left, top]);
+ this.polygonCoords.push([event.x, event.y]);
+ }
+ }
+ this.stage.paintSelectPolygon(left, top, this.polygonPoints);
+ }),
+ (this.selectRectHandle = function (event) {
+ var left = event.offsetLeft,
+ top = event.offsetTop,
+ mouseLeft = this.mouseDownEvent.offsetLeft,
+ mouseTop = this.mouseDownEvent.offsetTop,
+ x = left >= mouseLeft ? mouseLeft : left,
+ y = top >= mouseTop ? mouseTop : top,
+ dx = Math.abs(event.dx) * this.scaleX,
+ dy = Math.abs(event.dy) * this.scaleY;
+ this.stage.paintSelectRect(x, y, dx, dy);
+ x =
+ event.x >= this.mouseDownEvent.x
+ ? this.mouseDownEvent.x
+ : event.x;
+ y =
+ event.y >= this.mouseDownEvent.y
+ ? this.mouseDownEvent.y
+ : event.y;
+ var width = x + Math.abs(event.dx),
+ height = y + Math.abs(event.dy);
+ this.polygonCoords = [
+ [x, y],
+ [width, y],
+ [width, height],
+ [x, height],
+ ];
+ }),
+ (this.mousemoveHandler = function (event) {
+ var mouseEvent = self.toSceneEvent(event);
+ var targetEle = self.getElementByXY(mouseEvent.x, mouseEvent.y);
+ if (null != targetEle) {
+ if (
+ self.mouseOverelement &&
+ self.mouseOverelement !== targetEle
+ ) {
+ mouseEvent.target = targetEle;
+ self.mouseOverelement.mouseoutHandler(mouseEvent);
+ }
+ self.mouseOverelement = targetEle;
+ if (!targetEle.isMouseOver) {
+ mouseEvent.target = targetEle;
+ targetEle.mouseoverHandler(mouseEvent);
+ self.dispatchEvent("mouseover", mouseEvent);
+ } else {
+ mouseEvent.target = targetEle;
+ }
+ } else {
+ if (self.mouseOverelement) {
+ mouseEvent.target = targetEle;
+ self.mouseOverelement.mouseoutHandler(mouseEvent);
+ self.mouseOverelement = null;
+ self.dispatchEvent("mouseout", mouseEvent);
+ } else {
+ mouseEvent.target = null;
+ self.dispatchEvent("mousemove", mouseEvent);
+ }
+ }
+ }),
+ (this.mouseoverHandler = function (a) {
+ var b = this.toSceneEvent(a);
+ this.dispatchEvent("mouseover", b);
+ }),
+ (this.mouseoutHandler = function (a) {
+ var b = this.toSceneEvent(a);
+ this.dispatchEvent("mouseout", b);
+ }),
+ (this.clickHandler = function (a) {
+ var b = this.toSceneEvent(a);
+ this.currentElement &&
+ ((b.target = this.currentElement),
+ this.currentElement.clickHandler(b)),
+ this.dispatchEvent("click", b);
+ }),
+ (this.dbclickHandler = function (a) {
+ var b = this.toSceneEvent(a);
+ this.currentElement
+ ? ((b.target = this.currentElement),
+ this.currentElement.dbclickHandler(b))
+ : this.cancleAllSelected(),
+ this.dispatchEvent("dbclick", b);
+ }),
+ (this.keydownHandler = function (event) {
+ this.dispatchEvent("keydown", event);
+ }),
+ (this.keyupHandler = function (event) {
+ this.dispatchEvent("keyup", event);
+ }),
+ (this.addEventListener = function (a, b) {
+ var c = this,
+ d = function (a) {
+ b.call(c, a);
+ };
+ return this.messageBus.subscribe(a, d), this;
+ }),
+ (this.removeEventListener = function (event) {
+ this.messageBus.unsubscribe(event);
+ }),
+ (this.removeAllEventListener = function () {
+ this.messageBus = new DGraph.util.MessageBus();
+ }),
+ (this.dispatchEvent = function (a, b) {
+ return this.messageBus.publish(a, b), this;
+ });
+ var eventNames =
+ "click,dbclick,mousedown,mouseup,mouseover,mouseout,mousemove,mousedrag,keydown,keyup".split(
+ ",",
+ ),
+ self = this;
+ return (
+ eventNames.forEach(function (eventName) {
+ self[eventName] = function (event) {
+ null != event
+ ? this.addEventListener(eventName, event)
+ : this.dispatchEvent(eventName);
+ };
+ }),
+ (this.zoom = function (scaleX, scaleY) {
+ null != scaleX && 0 != scaleX && (this.scaleX = scaleX),
+ null != scaleY && 0 != scaleY && (this.scaleY = scaleY);
+ }),
+ (this.zoomOut = function (scale) {
+ if (this.scaleX <= this.scaleRange[1]) {
+ 0 != scale &&
+ (null == scale && (scale = 0.8),
+ (this.scaleX /= scale),
+ (this.scaleY /= scale));
+ }
+ }),
+ (this.zoomIn = function (scale) {
+ if (this.scaleX >= this.scaleRange[0]) {
+ 0 != scale &&
+ (null == scale && (scale = 0.8),
+ (this.scaleX *= scale),
+ (this.scaleY *= scale));
+ }
+
+ }),
+ (this.getBound = function () {
+ return {
+ left: 0,
+ top: 0,
+ right: this.stage.width,
+ bottom: this.stage.height,
+ width: this.stage.width,
+ height: this.stage.height,
+ };
+ }),
+ (this.getElementsBound = function () {
+ if (this.childs.length == 0) {
+ return null;
+ }
+ return this.getBoundWithElemets(this.childs);
+ }),
+ (this.getBoundWithElemets = function (elements) {
+ var bound = {
+ left: Number.MAX_VALUE,
+ right: -Number.MAX_VALUE,
+ top: Number.MAX_VALUE,
+ bottom: -Number.MAX_VALUE,
+ };
+ elements
+ .filter(function (it) {
+ return it.visible && it instanceof DGraph.Node;
+ })
+ .forEach(function (node) {
+ if (bound.left > node.x) {
+ bound.left = node.x;
+ bound.leftNode = node;
+ }
+ if (bound.right < node.x + node.width) {
+ bound.right = node.x + node.width;
+ bound.rightNode = node;
+ }
+ if (bound.top > node.y) {
+ bound.top = node.y;
+ bound.topNode = node;
+ }
+ if (bound.bottom < node.y + node.height) {
+ bound.bottom = node.y + node.height;
+ bound.bottomNode = node;
+ }
+ });
+ if (bound.leftNode.parentContainer) {
+ bound.left = bound.left - bound.leftNode.parentContainer.padding;
+ }
+ if (bound.rightNode.parentContainer) {
+ bound.right =
+ bound.right + bound.rightNode.parentContainer.padding;
+ }
+ if (bound.bottomNode.parentContainer) {
+ bound.bottom =
+ bound.bottom + bound.bottomNode.parentContainer.padding;
+ }
+ if (bound.topNode.parentContainer) {
+ bound.top =
+ bound.top -
+ bound.topNode.parentContainer.padding -
+ bound.topNode.parentContainer.headerHeight;
+ }
+ bound.width = bound.right - bound.left;
+ bound.height = bound.bottom - bound.top;
+ return bound;
+ }),
+ (this.translateToCenter = function (context) {
+ var bound = this.getElementsBound();
+ if (bound != null) {
+ var translateX = 0,
+ translateY = 0;
+ if (context) {
+
+ translateX =
+ context.canvas.width / 2 - (bound.left + bound.right) / 2;
+ translateY =
+ context.canvas.height / 2 - (bound.top + bound.bottom) / 2;
+ } else {
+
+ (translateX =
+ this.stage.width / 2 - (bound.left + bound.right) / 2),
+ (translateY =
+ this.stage.height / 2 - (bound.top + bound.bottom) / 2);
+ }
+ this.translateX = translateX;
+ this.translateY = translateY;
+ }
+ }),
+ (this.setCenter = function (x, y) {
+ var offsetX = x - this.stage.width / 2;
+ var offsetY = y - this.stage.height / 2;
+ this.translateX = -offsetX;
+ this.translateY = -offsetY;
+ }),
+ (this.centerAndZoom = function (scaleX, scaleY, context) {
+ this.translateToCenter(context);
+ if (null == scaleX || null == scaleY) {
+ var bound = this.getElementsBound();
+ if (bound != null) {
+ var width = bound.right - bound.left;
+ var height = bound.bottom - bound.top;
+ var scaleX = 1,
+ scaleY = 1;
+ if (context) {
+ scaleX = context.canvas.width / width;
+ scaleY = context.canvas.height / height;
+ } else {
+ scaleX = this.stage.width / width;
+ scaleY = this.stage.height / height;
+ }
+ var scale = Math.min(scaleX, scaleY);
+ if (scale > 1) {
+ scale = 1;
+ }
+ this.zoom(scale, scale);
+ }
+ } else {
+ this.zoom(scaleX, scaleY);
+ }
+ }),
+ (this.getCenterLocation = function () {
+ var self = this;
+ return { x: self.stage.width / 2, y: self.stage.height / 2 };
+ }),
+ self
+ );
+ }
+ Scene.prototype = new DGraph.Element();
+ DGraph.Scene = Scene;
+ })(DGraph),
+ (function (DGraph) {
+ function DisplayElement() {
+ (this.initialize = function () {
+ DisplayElement.prototype.initialize.apply(this, arguments),
+ (this.elementType = "displayElement"),
+ (this.x = 0),
+ (this.y = 0),
+ (this.width = 40),
+ (this.height = 40),
+ (this.radius = 20);
+ this.size = 40;
+ (this.visible = true),
+ (this.alpha = 1),
+ (this.rotate = 0),
+ (this.scaleX = 1),
+ (this.scaleY = 1),
+ (this.strokeColor = "22,255,22"),
+ (this.borderColor = "22,255,22"),
+ (this.fillColor = "22,255,22"),
+ (this.shadow = false),
+ (this.shadowBlur = 20),
+ (this.shadowColor = "rgba(20,200,20,0.5)"),
+ (this.shadowOffsetX = 3),
+ (this.shadowOffsetY = 6),
+ (this.transformAble = false),
+ (this.animate = false),
+ (this.zIndex = 0);
+ this.properties = {};
+ }),
+ this.initialize(),
+ (this.paint = function (ctx) {
+ ctx.beginPath(),
+ ctx.rect(
+ -this.width / 2,
+ -this.height / 2,
+ this.width,
+ this.height,
+ );
+ if (this.fillColor) {
+ (ctx.fillStyle = `rgba(${this.fillColor},${this.alpha})`),
+ ctx.fill();
+ }
+ (ctx.strokeStyle = `rgba(${this.strokeColor},${this.alpha})`),
+ ctx.stroke(),
+ ctx.closePath();
+ }),
+ (this.getLocation = function () {
+ return { x: this.x, y: this.y };
+ }),
+ (this.setLocation = function (x, y) {
+ this.x = x;
+ this.y = y;
+ return this;
+ }),
+ (this.getCenterLocation = function () {
+ return { x: this.x + this.width / 2, y: this.y + this.height / 2 };
+ }),
+ (this.setCenterLocation = function (x, y) {
+ this.x = x - this.width / 2;
+ this.y = y - this.height / 2;
+ return this;
+ }),
+ (this.getSize = function () {
+ return { width: this.width, height: this.height };
+ }),
+ (this.setSize = function (width, height) {
+ this.width = Number(width) || 40;
+ this.height = Number(height) || 40;
+ this.raduis = Math.round(this.width / 2);
+ return this;
+ }),
+ (this.getBound = function () {
+ return {
+ left: this.x - this.borderWidth,
+ top: this.y - this.borderWidth,
+ right: this.x + this.width + this.borderWidth,
+ bottom: this.y + this.height + this.borderWidth,
+ width: this.width,
+ height: this.height,
+ };
+ }),
+ (this.setBound = function (x, y, width, height) {
+ this.setLocation(x, y);
+ this.setSize(width, height);
+ return this;
+ }),
+ (this.getPosition = function (textPosition) {
+ var pos,
+ bound = this.getBound();
+ switch (textPosition) {
+ case "Top_Left":
+ pos = { x: bound.left, y: bound.top };
+ break;
+ case "Top_Center":
+ pos = { x: this.cx, y: bound.top };
+ break;
+ case "Top_Right":
+ pos = { x: bound.right, y: bound.top };
+ break;
+ case "Middle_Left":
+ pos = { x: bound.left, y: this.cy };
+ break;
+ case "Middle_Center":
+ pos = { x: this.cx, y: this.cy };
+ break;
+ case "Middle_Right":
+ pos = { x: bound.right, y: this.cy };
+ break;
+ case "Bottom_Left":
+ pos = { x: bound.left, y: bound.bottom };
+ break;
+ case "Bottom_Center":
+ pos = { x: this.cx, y: bound.bottom };
+ break;
+ case "Bottom_Right":
+ pos = { x: bound.right, y: bound.bottom };
+ break;
+ default:
+ pos = { x: this.cx, y: this.cy };
+ break;
+ }
+ return pos;
+ });
+ }
+ function InteractiveElement() {
+ (this.initialize = function () {
+ InteractiveElement.prototype.initialize.apply(this, arguments),
+ (this.elementType = "interactiveElement"),
+ (this.dragable = false),
+ (this.selected = false),
+ (this.showSelected = false),
+ (this.isMouseOver = false),
+ (this.selectedLocation = null),
+ (this.showBackGround = false),
+ (this.animate = false);
+ }),
+ this.initialize(),
+ (this.paintMouseover = function (ctx) {
+ this.showSelected = true;
+ }),
+ (this.isInBound = function (x, y) {
+ if (this.shape == "rect") {
+ var width = this.width * this.scaleX;
+ var height = this.height * this.scaleY;
+ if (this.rotate == 0) {
+ return (
+ x > this.cx - width / 2 &&
+ x < this.cx + width / 2 &&
+ y > this.cy - height / 2 &&
+ y < this.cy + height / 2
+ );
+ } else {
+ var cpx = this.cx,
+ cpy = this.cy;
+ var angle = -((this.rotate * Math.PI) / 180);
+ var x0 =
+ (x - cpx) * Math.cos(angle) -
+ (y - cpy) * Math.sin(angle) +
+ cpx;
+ var y0 =
+ (x - cpx) * Math.sin(angle) +
+ (y - cpy) * Math.cos(angle) +
+ cpy;
+ return (
+ x0 > this.cx - width / 2 &&
+ x0 < this.cx + width / 2 &&
+ y0 > this.cy - height / 2 &&
+ y0 < this.cy + height / 2
+ );
+ }
+ }
+ else {
+ console.log(this.radius)
+ return (
+ (x - this.cx) * (x - this.cx) + (y - this.cy) * (y - this.cy) <
+ this.radius * this.scaleX * this.radius * this.scaleX
+ );
+ }
+ }),
+ (this.selectedHandler = function () {
+ (this.selected = true),
+ (this.selectedLocation = { x: this.x, y: this.y });
+ }),
+ (this.unselectedHandler = function () {
+ (this.selected = false), (this.selectedLocation = null);
+ }),
+ (this.dbclickHandler = function (event) {
+ this.dispatchEvent("dbclick", event);
+ }),
+ (this.clickHandler = function (event) {
+ this.dispatchEvent("click", event);
+ }),
+ (this.mousedownHander = function (a) {
+ this.dispatchEvent("mousedown", a);
+ }),
+ (this.mouseupHandler = function (event) {
+ this.dispatchEvent("mouseup", event);
+ }),
+ (this.mouseoverHandler = function (event) {
+ (this.isMouseOver = true), this.dispatchEvent("mouseover", event);
+ }),
+ (this.mousemoveHandler = function (event) {
+ this.dispatchEvent("mousemove", event);
+ }),
+ (this.mouseoutHandler = function (event) {
+ (this.isMouseOver = false),
+ (this.showSelected = false),
+ this.dispatchEvent("mouseout", event);
+ }),
+ (this.mousedragHandler = function (event) {
+ var x = this.selectedLocation.x + event.dx,
+ y = this.selectedLocation.y + event.dy;
+ this.setLocation(x, y);
+ this.dispatchEvent("mousedrag", event);
+ }),
+ (this.addEventListener = function (eventName, fucn) {
+ var self = this,
+ event = function (e) {
+ fucn.call(self, e);
+ };
+ return (
+ this.messageBus ||
+ (this.messageBus = new DGraph.util.MessageBus()),
+ this.messageBus.subscribe(eventName, event),
+ this
+ );
+ }),
+ (this.dispatchEvent = function (eventName, fucn) {
+ return this.messageBus
+ ? (this.messageBus.publish(eventName, fucn), this)
+ : null;
+ }),
+ (this.removeEventListener = function (event) {
+ this.messageBus.unsubscribe(event);
+ }),
+ (this.removeAllEventListener = function () {
+ this.messageBus = new DGraph.util.MessageBus();
+ });
+ var self = this;
+ var eventNames = [
+ "click",
+ "dbclick",
+ "mousedown",
+ "mouseup",
+ "mouseover",
+ "mouseout",
+ "mousemove",
+ "mousedrag",
+ ];
+ eventNames.forEach(function (eventName) {
+ self[eventName] = function (event) {
+ null != event
+ ? this.addEventListener(eventName, event)
+ : this.dispatchEvent(eventName);
+ };
+ });
+ }
+ (DisplayElement.prototype = new DGraph.Element()),
+ Object.defineProperties(DisplayElement.prototype, {
+ cx: {
+ get: function () {
+ return this.x + this.width / 2;
+ },
+ set: function (x) {
+ this.x = x - this.width / 2;
+ },
+ },
+ cy: {
+ get: function () {
+ return this.y + this.height / 2;
+ },
+ set: function (y) {
+ this.y = y - this.height / 2;
+ },
+ },
+ radius: {
+ get: function () {
+ return Math.round(this.width / 2);
+ },
+ set: function (r) {
+ this.width = r * 2;
+ },
+ },
+ }),
+ (InteractiveElement.prototype = new DisplayElement()),
+ (DGraph.DisplayElement = DisplayElement),
+ (DGraph.InteractiveElement = InteractiveElement);
+ })(DGraph),
+ (function (DGraph) {
+ function Node(name) {
+ (this.initialize = function (name) {
+ Node.prototype.initialize.apply(this, arguments),
+ (this.elementType = "node"),
+ (this.zIndex = DGraph.Node_zIndex),
+ (this.text = name),
+ (this.font = "normal 13px Arial"),
+ (this.fontColor = "20,20,20"),
+ (this.borderWidth = 0),
+ (this.borderColor = "20,255,20"),
+ (this.borderAlpha = 1),
+ (this.selectedBorderColor = "255,0,0"),
+ (this.selectedBorderWidth = 10),
+ (this.selectedBorderAlpha = 0.7),
+ (this.borderRadius = 0),
+ (this.shadowColor = "20,255,20"),
+ (this.shadowBlur = 10),
+ (this.dragable = true),
+ (this.textPosition = "Middle_Center"),
+ (this.textOffsetX = 0),
+ (this.textOffsetY = 0),
+ (this.transformAble = true),
+ (this.inLinks = null),
+ (this.outLinks = null);
+ this.width = 60;
+ this.height = 60;
+ (this.labelBackGround = null),
+ (this.labelBorderWidth = 0),
+ (this.labelBorderColor = "255,255,255");
+ this.fillStyle = null;
+ this.textLines = [];
+ this.fontWidth = 18;
+ this.icon = {
+ font: "bold 20px Consolas",
+ text: null,
+ color: "255,255,255",
+ left: -this.width,
+ top: this.height / 2,
+ };
+ this.textCache = {
+ sigleWidth: 0,
+ maxWidth: 0,
+ lineCount: 0,
+ font: null,
+ };
+ }),
+ this.initialize(name),
+ (this.drawNodeImg = function (ctx, img, x, y, r) {
+
+ if (img && img.width) {
+
+ if (this.shape == "circle") {
+ r = r > 2 ? r : 2;
+ if (r < img.width / 2) {
+ ctx.arc(x + r, y + r, r, 0, 2 * Math.PI);
+ ctx.clip();
+ ctx.drawImage(img, x, y, 2 * r, 2 * r);
+ } else {
+ ctx.drawImage(
+ img,
+ -img.width / 2,
+ -img.height / 2,
+ img.width,
+ img.height,
+ );
+ }
+ } else if (this.shape == "rect") {
+ ctx.drawImage(img, x, y, this.width, this.height);
+ } else {
+ ctx.drawImage(
+ img,
+ -img.width / 2,
+ -img.height / 2,
+ img.width,
+ img.height,
+ );
+ }
+ }
+ }),
+ (this.paint = function (ctx, onlyShape) {
+ if (this.drawNode && typeof this.drawNode === "function") {
+ if (this.showBackGround) {
+ ctx.save(), ctx.beginPath();
+ ctx.rect(
+ -this.width / 2 - 5,
+ -this.height / 2 - 5,
+ this.width + 10,
+ this.height + 10,
+ );
+ ctx.closePath();
+ ctx.fillStyle = "rgba(220,220,220,0.5)";
+ ctx.fill();
+ ctx.restore();
+ }
+ this.drawNode(ctx, onlyShape);
+ return false;
+ }
+ this.drawOriginalNode(ctx, onlyShape);
+ }),
+ (this.drawOriginalNode = function (ctx, onlyShape) {
+ this.drawShape(ctx, onlyShape);
+ if (this.image && !onlyShape) {
+ var globleAlpha = ctx.globalAlpha;
+ ctx.save();
+ ctx.globalAlpha = this.alpha;
+ this.drawNodeImg(
+ ctx,
+ this.image,
+ -this.width / 2,
+ -this.height / 2,
+ this.width / 2,
+ );
+ ctx.globalAlpha = globleAlpha;
+ ctx.restore();
+ }
+ if (!onlyShape && !this.hideText) {
+ if (this.icon && this.icon.text) {
+ this.paintIcon(ctx);
+ }
+ this.paintText(ctx), this.paintTipText(ctx);
+ this.paintHeadTip(ctx);
+ }
+ }),
+ (this.drawShape = function (ctx, onlyShape) {
+ ctx.save();
+ ctx.beginPath();
+ this.paintShape(ctx);
+ if (!onlyShape) {
+ if (this.lineDash && this.lineDash.length > 1) {
+ ctx.setLineDash(this.lineDash);
+ }
+ if (
+ (this.showSelected || this.selected) &&
+ this.selectedBorderWidth > 0
+ ) {
+ ctx.lineWidth = this.borderWidth + this.selectedBorderWidth;
+ ctx.strokeStyle = `rgba(${this.selectedBorderColor},${this.alpha * this.selectedBorderAlpha})`;
+ ctx.stroke();
+ }
+ if (
+ !this.selected &&
+ !this.showSelected &&
+ this.borderWidth > 0
+ ) {
+ ctx.lineWidth = this.borderWidth;
+ ctx.strokeStyle = this.strokeStyle
+ ? this.strokeStyle
+ : `rgba(${this.borderColor},${this.alpha * this.borderAlpha})`;
+ ctx.stroke();
+ }
+ if (this.fillColor || onlyShape) {
+ this.paintShadow(ctx);
+ ctx.fillStyle = this.fillStyle
+ ? this.fillStyle
+ : `rgba(${this.fillColor},${this.alpha})`;
+ ctx.fill();
+ }
+ } else {
+ if (this.fillStyle) {
+ ctx.fillStyle = this.fillStyle;
+ ctx.fill();
+ } else {
+ if (this.fillColor) {
+ ctx.fillStyle = `rgba(${this.fillColor},${this.alpha})`;
+ ctx.fill();
+ } else {
+ ctx.lineWidth = this.borderWidth;
+ ctx.strokeStyle = `rgba(${this.borderColor},${this.alpha})`;
+ ctx.stroke();
+ }
+ }
+ }
+ ctx.restore();
+ }),
+ (this.paintShape = function (ctx) {
+ switch (this.shape) {
+ case "rect":
+ if (!this.borderRadius) {
+ ctx.rect(
+ -this.width / 2,
+ -this.height / 2,
+ this.width,
+ this.height,
+ );
+ } else {
+ var width = this.width;
+ var height = this.height;
+ var r2d = Math.PI / 180;
+ var r = this.borderRadius;
+ var x = -width / 2,
+ y = -height / 2;
+ if (width - 2 * r < 0) {
+ r = width / 2;
+ }
+ if (height - 2 * r < 0) {
+ r = height / 2;
+ }
+ ctx.moveTo(x + r, y);
+ ctx.lineTo(x + width - r, y);
+ ctx.arc(x + width - r, y + r, r, r2d * 270, r2d * 360, false);
+ ctx.lineTo(x + width, y + height - r);
+ ctx.arc(x + width - r, y + height - r, r, 0, r2d * 90, false);
+ ctx.lineTo(x + r, y + height);
+ ctx.arc(x + r, y + height - r, r, r2d * 90, r2d * 180, false);
+ ctx.lineTo(x, y + r);
+ ctx.arc(x + r, y + r, r, r2d * 180, r2d * 270, false);
+ ctx.closePath();
+ }
+ break;
+ case "ellipse":
+ ctx.ellipse(
+ 0,
+ 0,
+ this.radius,
+ this.radius / 2,
+ 0,
+ 0,
+ 2 * Math.PI,
+ );
+ break;
+ case "square":
+ ctx.rect(
+ -this.radius,
+ -this.radius,
+ this.radius * 2,
+ this.radius * 2,
+ );
+ break;
+ case "triangle":
+ ctx.moveTo(0, -this.radius);
+ ctx.lineTo(-this.radius, this.radius);
+ ctx.lineTo(this.radius, this.radius);
+ ctx.closePath();
+ break;
+ case "star":
+ var r = this.radius * 2 * 0.41;
+ for (var n = 0; n < 10; n++) {
+ var radius = n % 2 === 0 ? r * 1.3 : r * 0.5;
+ ctx.lineTo(
+ radius * Math.sin((n * 2 * Math.PI) / 10),
+ 0.1 * r - radius * Math.cos((n * 2 * Math.PI) / 10),
+ );
+ }
+ ctx.closePath();
+ break;
+ case "polygon":
+ var degree = (2 * Math.PI) / 6;
+ for (var i = 0; i < 6; i++) {
+ var x = Math.cos(i * degree);
+ var y = Math.sin(i * degree);
+ ctx.lineTo(x * this.radius, y * this.radius);
+ }
+ ctx.closePath();
+ break;
+ case "circle":
+ this.radius = this.radius < 2 ? 2 : this.radius;
+ ctx.arc(0, 0, this.radius, 0, Math.PI * 2, false);
+
+ break;
+ default:
+ this.radius = this.radius < 2 ? 2 : this.radius;
+ ctx.arc(0, 0, this.radius, 0, 2 * Math.PI, true);
+ break;
+ }
+ }),
+ (this.paintTipText = function (ctx) {
+ if (this.tipText) {
+ var b = this.alarmColor || "0,250,0",
+ c = this.alarmAlpha || 0.8 * this.alpha;
+ ctx.font = this.alarmFont || "10px Consolas";
+ var d = ctx.measureText(this.tipText).width + 6,
+ e = ctx.measureText("田").width + 6,
+ f = this.width / 2 - d / 2,
+ g = -this.height / 2 - e - 8;
+ (ctx.strokeStyle = `rgba(${b},${c})`),
+ (ctx.fillStyle = `rgba(${b},${c})`),
+ ctx.DGraphRoundRect(
+ this.width / 3,
+ -this.height / 2,
+ d + 5,
+ e,
+ 8,
+ ),
+ ctx.stroke(),
+ ctx.fill(),
+ (ctx.fillStyle = `rgba(250,250,250,${this.alpha})`),
+ ctx.fillText(
+ this.tipText,
+ this.width / 3 + 5,
+ -this.height / 2 + 12,
+ );
+ }
+ }),
+ (this.paintText = function (ctx) {
+ var self = this;
+ // this.showlabel = true;
+ var label;
+ label = this.text = this.label;
+ // if (this.showlabel) {
+ // label = this.text = this.label;
+ // } else {
+ // label = this.text = this.label;
+ // return;
+ // }
+ if (label) {
+ var pos;
+ ctx.save();
+ ctx.font = this.font;
+ var singleTextWidth = 0;
+ ctx.fillStyle = `rgba(${this.fontColor},${this.alpha})`;
+ if (this.wrapText == true) {
+ singleTextWidth = ctx.measureText("田").width;
+ var textArr = this.buildTextArray(label);
+ var maxWidth = 0;
+ ctx.textAlign = "center";
+ textArr.forEach(function (text, i) {
+ text = String(text);
+ maxWidth = Math.max(
+ maxWidth,
+ ctx.measureText(text.replace(/ /g, "田")).width,
+ );
+ ctx.fillText(
+ text,
+ 0,
+ -((singleTextWidth / 2) * textArr.length) +
+ (i + 1) * singleTextWidth,
+ );
+ });
+ this.width = this.width-0.5;
+ // maxWidth + 8 < this.width ? this.width : maxWidth + 8;
+ } else {
+ this.processLabel(ctx);
+ singleTextWidth = this.textCache.sigleWidth;
+ var lineCount = this.textLines.length;
+ var labelHeight = lineCount * singleTextWidth;
+ if (this.labelBackGround) {
+ pos = this.getTextPostion(
+ this.textPosition,
+ this.textCache.maxWidth,
+ singleTextWidth,
+ );
+ ctx.save();
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = `rgba(${this.labelBorderColor},${this.alpha})`;
+ ctx.fillStyle = `rgba(${this.labelBackGround},${this.alpha})`;
+ ctx.DGraphRoundRect(
+ pos.x - 5,
+ pos.y - singleTextWidth * 1.45,
+ this.textCache.maxWidth + 10,
+ labelHeight + singleTextWidth + (lineCount == 1 ? 0 : 4),
+ 5,
+ );
+ ctx.stroke(), ctx.fill(), ctx.restore();
+ }
+ if (this.labelBorderWidth > 0) {
+ ctx.lineWidth = this.labelBorderWidth;
+ ctx.strokeStyle = `rgba(${this.labelBorderColor},${this.alpha})`;
+ ctx.lineJoin = "round";
+ ctx.lineCap = "round";
+ }
+ if (lineCount == 1) {
+ pos = this.getTextPostion(
+ this.textPosition,
+ this.textCache.maxWidth,
+ singleTextWidth,
+ );
+ this.labelBorderWidth > 0
+ ? ctx.strokeText(this.textLines[0], pos.x, pos.y)
+ : null;
+ ctx.fillText(this.textLines[0], pos.x, pos.y - 1);
+ } else {
+ for (let i = 0; i < lineCount; i++) {
+ pos = this.getTextPostion(
+ this.textPosition,
+ ctx.measureText(this.textLines[i]).width,
+ singleTextWidth,
+ );
+ this.labelBorderWidth > 0
+ ? ctx.strokeText(
+ this.textLines[i],
+ pos.x,
+ pos.y + i * singleTextWidth + (i == 0 ? 0 : 2 * i),
+ )
+ : null;
+ ctx.fillText(
+ this.textLines[i],
+ pos.x,
+ pos.y - 1 + i * singleTextWidth + (i == 0 ? 0 : 2 * i),
+ );
+ }
+ }
+ }
+ ctx.restore();
+ }
+ }),
+ (this.processLabel = function (ctx) {
+ this.textLines = String(this.label).split("\n");
+ if (
+ this.textCache.sigleWidth == 0 ||
+ this.textCache.lineCount != this.textLines.length ||
+ this.textCache.font != this.font
+ ) {
+ this.textCache.sigleWidth = ctx.measureText("田").width;
+ this.textCache.font = this.font;
+ this.textCache.lineCount = this.textLines.length;
+ if (this.textLines.length == 1) {
+ this.textCache.maxWidth = ctx.measureText(
+ this.textLines[0],
+ ).width;
+ } else {
+ for (let i = 0; i < this.textLines.length; i++) {
+ this.textCache.maxWidth = Math.max(
+ ctx.measureText(this.textLines[i]).width,
+ this.textCache.maxWidth,
+ );
+ }
+ }
+ }
+ }),
+ (this.buildTextArray = function (label) {
+ var length = String(label).length;
+ var textArr = [];
+ if (length < 5) {
+ textArr.push(label);
+ } else if (length >= 5 && length <= 9) {
+ textArr.push(label.substring(0, 4));
+ textArr.push(label.substring(4));
+ } else if (length > 9 && length <= 13) {
+ textArr.push(label.substring(0, 4));
+ textArr.push(label.substring(4, 9));
+ textArr.push(label.substring(9));
+ } else {
+ textArr.push(label.substring(0, 4));
+ textArr.push(label.substring(4, 9));
+ textArr.push(label.substring(9, 12) + "..");
+ }
+ return textArr;
+ });
+ (this.paintShadow = function (ctx) {
+ if (this.showShadow && this.selected) {
+ (ctx.shadowBlur = this.shadowBlur),
+ (ctx.shadowColor = `rgba(${this.shadowColor},${this.alpha * 0.9})`),
+ (ctx.shadowOffsetX = 0),
+ (ctx.shadowOffsetY = 0);
+ }
+ }),
+ (this.paintIcon = function (ctx) {
+ ctx.save(),
+ (ctx.fillStyle = `rgba(${this.icon.color},${this.alpha})`);
+ (ctx.font = this.icon.font),
+ ctx.fillText(
+ this.icon.text,
+ this.icon.left || 5,
+ this.icon.top || 5,
+ ),
+ ctx.restore();
+ }),
+ (this.paintHeadTip = function (ctx) {
+ if (this.headTipText) {
+ var radius = this.headTipRadius || 0;
+ var padding = 16;
+ ctx.save();
+ ctx.font = this.headTipFont || "normal 13px Arial";
+ var width = ctx.measureText(this.headTipText).width + padding;
+ var height = ctx.measureText("田").width + padding - 2;
+ radius = radius > height / 2 ? height / 2 : radius;
+ ctx.translate(-width / 2, -height - this.height / 2 - 6);
+ ctx.beginPath();
+ ctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
+ ctx.lineTo(width / 2.0 + 4, height);
+ ctx.lineTo(width / 2.0, height + 6);
+ ctx.lineTo(width / 2.0 - 4, height);
+ ctx.lineTo(radius, height);
+ ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
+ ctx.lineTo(0, radius);
+ ctx.arc(radius, radius, radius, Math.PI, (Math.PI * 3) / 2);
+ ctx.lineTo(width - radius, 0);
+ ctx.arc(
+ width - radius,
+ radius,
+ radius,
+ (Math.PI * 3) / 2,
+ Math.PI * 2,
+ );
+ ctx.lineTo(width, height - radius);
+ ctx.closePath();
+ ctx.fillStyle = `rgba(${this.headTipColor || "250,50,50"},${this.alpha})`;
+ ctx.fill();
+ ctx.translate(width / 2, height / 2);
+ ctx.textBaseline = "middle";
+ ctx.textAlign = "center";
+ ctx.fillStyle = `rgba(${this.headTipFontColor || "250,250,250"},${this.alpha})`;
+ ctx.fillText(this.headTipText, 0, 0);
+ ctx.restore();
+ }
+ }),
+ (this.getTextPostion = function (
+ textPosition,
+ textWidth,
+ textHeight,
+ ) {
+ var position = null;
+ return (
+ null == textPosition || "Bottom_Center" == textPosition
+ ? (position = {
+ x: -this.width / 2 + (this.width - textWidth) / 2,
+ y: this.height / 2 + textHeight,
+ })
+ : "Top_Center" == textPosition
+ ? (position = {
+ x: -this.width / 2 + (this.width - textWidth) / 2,
+ y: -this.height / 2 - textHeight / 2,
+ })
+ : "Top_Right" == textPosition
+ ? (position = {
+ x: this.width / 2,
+ y: -this.height / 2 - textHeight / 2,
+ })
+ : "Top_Left" == textPosition
+ ? (position = {
+ x: -this.width / 2 - textWidth,
+ y: -this.height / 2 - textHeight / 2,
+ })
+ : "Bottom_Right" == textPosition
+ ? (position = {
+ x: this.width / 2,
+ y: this.height / 2 + textHeight,
+ })
+ : "Bottom_Left" == textPosition
+ ? (position = {
+ x: -this.width / 2 - textWidth,
+ y: this.height / 2 + textHeight,
+ })
+ : "Middle_Center" == textPosition
+ ? (position = {
+ x:
+ -this.width / 2 +
+ (this.width - textWidth) / 2,
+ y: textHeight / 2,
+ })
+ : "Middle_Right" == textPosition
+ ? (position = {
+ x: this.width / 2,
+ y: textHeight / 2,
+ })
+ : "Middle_Left" == textPosition &&
+ (position = {
+ x: -this.width / 2 - textWidth,
+ y: textHeight / 2,
+ }),
+ null == position
+ ? (position = {
+ x: -this.width / 2 + (this.width - textWidth) / 2,
+ y: this.height / 2 + textHeight,
+ })
+ : position,
+ null != this.textOffsetX && (position.x += this.textOffsetX),
+ null != this.textOffsetY && (position.y += this.textOffsetY),
+ position
+ );
+ }),
+ (this.setImage = function (imgS) {
+ if (null == imgS) throw new Error("image is null!");
+ var self = this;
+ var image = DGraph.imgStore[imgS];
+ if (image != null) {
+ self.image = image;
+ return;
+ }
+ if ("string" == typeof imgS) {
+ var img = new Image();
+ img.setAttribute("crossOrigin", "Anonymous");
+ img.src = imgS;
+ img.onload = function () {
+ self.image = img;
+ };
+ DGraph.imgStore[imgS] = img;
+ } else {
+ (this.image = imgS), this.setSize(imgS.width, imgS.height);
+ }
+ }),
+ (this.removeHandler = function (a) {
+ var self = this;
+ this.outLinks &&
+ (this.outLinks.forEach(function (link) {
+ link.source === self && a.remove(link);
+ }),
+ (this.outLinks = null));
+ this.inLinks &&
+ (this.inLinks.forEach(function (link) {
+ link.target === self && a.remove(link);
+ }),
+ (this.inLinks = null));
+ });
+ }
+ (Node.prototype = new DGraph.InteractiveElement()), (DGraph.Node = Node);
+ })(DGraph),
+ (function (DGraph) {
+ function mergeLine(source, target) {
+ var lines = [];
+ if (null == source || null == target) return lines;
+ if (source.outLinks && target.inLinks)
+ for (var i = 0; i < source.outLinks.length; i++)
+ for (
+ var outLink = source.outLinks[i], j = 0;
+ j < target.inLinks.length;
+ j++
+ ) {
+ var inLink = target.inLinks[j];
+ outLink === inLink && lines.push(inLink);
+ }
+ return lines;
+ }
+ function findLines(source, target, twoDirect) {
+ if (twoDirect != null && twoDirect == true) {
+ var outLines = mergeLine(source, target),
+ inLines = mergeLine(target, source),
+ allLines = outLines.concat(inLines);
+ return allLines;
+ }
+ return mergeLine(source, target);
+ }
+ function findAllLines(line) {
+ var lines = findLines(line.source, line.target);
+ return (lines = lines.filter(function (_line) {
+ return line !== _line;
+ }));
+ }
+ function calLineNum(source, target, twoDirect) {
+ return findLines(source, target, twoDirect).length;
+ }
+ function Link(source, target, label) {
+ (this.initialize = function (source, target, label) {
+ Link.prototype.initialize.apply(this, arguments);
+ this.elementType = "link";
+ this.zIndex = DGraph.Link_zIndex;
+ (this.text = label),
+ (this.source = source),
+ (this.target = target),
+ this.source &&
+ null == this.source.outLinks &&
+ (this.source.outLinks = []),
+ this.source &&
+ null == this.source.inLinks &&
+ (this.source.inLinks = []),
+ this.target &&
+ null == this.target.inLinks &&
+ (this.target.inLinks = []),
+ this.target &&
+ null == this.target.outLinks &&
+ (this.target.outLinks = []),
+ null != this.source && this.source.outLinks.push(this),
+ null != this.target && this.target.inLinks.push(this),
+ this.caculateIndex(),
+ (this.font = "normal 13px Arial"),
+ (this.fontColor = "120,120,120"),
+ (this.lineWidth = 2),
+ (this.lineJoin = "round"),
+ (this.showShadow = false);
+ (this.shadowColor = "10,250,10"),
+ (this.selectedColor = "10,10,230"),
+ (this.selectedAlpha = 1);
+ this.background = null;
+ (this.transformAble = false),
+ (this.textOffsetX = 0),
+ (this.textOffsetY = 0),
+ (this.bundleOffset = 20),
+ (this.bundleGap = 30),
+ (this.groupNum = 1),
+ (this.curveness = 0.5),
+ (this.arrowsRadius = 5),
+ (this.showlabel = true),
+ (this.showArrow = true),
+ (this.arrowType = "arrow"),
+ (this.labelBackGround = null),
+ (this.labelBorderWidth = 0),
+ (this.labelBorderColor = "255,255,255");
+ this.path = [];
+ this.animate = false;
+ this.animateSpeed = 2;
+ this.animateBallIndex = 1;
+ this.animateBall = null;
+ this.animateBallColor = "255,0,0";
+ this.animateBallSize = Math.round(this.lineWidth * 2);
+ this.lineDashOffset = 0;
+ }),
+ (this.findInsertPoint = function (target, source) {
+ var line = DGraph.util.lineVir(
+ target.cx,
+ target.cy,
+ source.cx,
+ source.cy,
+ ),
+ bound = target.getBound(),
+ point = DGraph.util.intersectionLineBound(line, bound);
+ return point;
+ }),
+ (this.caculateIndex = function () {
+ var index = calLineNum(this.source, this.target, false);
+ if (index > 0) {
+ this.nodeIndex = index - 1;
+ }
+ }),
+ this.initialize(source, target, label),
+ (this.removeHandler = function () {
+ var self = this;
+ this.source &&
+ this.source.outLinks &&
+ (this.source.outLinks = this.source.outLinks.filter(function (b) {
+ return b !== self;
+ })),
+ this.target &&
+ this.target.inLinks &&
+ (this.target.inLinks = this.target.inLinks.filter(function (b) {
+ return b !== self;
+ }));
+ var lines = findAllLines(this);
+ lines.forEach(function (line, i) {
+ line.nodeIndex = i;
+ });
+ }),
+ (this.getStartPosition = function () {
+ var cpoint = { x: this.source.cx, y: this.source.cy };
+ return cpoint;
+ }),
+ (this.getEndPosition = function () {
+ var epoint = { x: this.target.cx, y: this.target.cy };
+ return (
+ (epoint = this.findInsertPoint(this.target, this.source)),
+ null == epoint &&
+ (epoint = { x: this.target.cx, y: this.target.cy }),
+ epoint
+ );
+ }),
+ (this.getPath = function () {
+ var startPoint = this.getStartPosition(),
+ endPoint = this.getEndPosition();
+ return [startPoint, endPoint];
+ }),
+ (this.paintLine = function (ctx, label) {}),
+ (this.paintArrow = function (ctx, g, h) {}),
+ (this.paint = function (ctx) {}),
+ (this.paintText = function (ctx, label) {}),
+ (this.isInBound = function (mouseX, mouseY) {
+ var self = this;
+ if (this.path.length > 0) {
+ var lineWidth = self.lineWidth;
+ if (self.labelBackHeight) {
+ lineWidth = Math.round(self.labelBackHeight / 2);
+ }
+ var flag = false;
+ for (var i = 1; i < this.path.length; i++) {
+ var startPoint = this.path[i - 1],
+ endPoint = this.path[i];
+ if (
+ true ==
+ DGraph.util.containStroke(
+ startPoint.x,
+ startPoint.y,
+ endPoint.x,
+ endPoint.y,
+ lineWidth,
+ mouseX,
+ mouseY,
+ )
+ ) {
+ flag = true;
+ break;
+ }
+ }
+ return flag;
+ } else {
+ if (self.bezierPoints) {
+ var pos = self.bezierPoints;
+ return DGraph.util.containBerzierStroke(
+ pos[0],
+ pos[1],
+ pos[2],
+ pos[3],
+ pos[4],
+ pos[5],
+ pos[6],
+ pos[7],
+ self.lineWidth,
+ mouseX,
+ mouseY,
+ );
+ }
+ if (self.quadraticPoints) {
+ var pos = self.quadraticPoints;
+ return DGraph.util.containQuadraticStroke(
+ pos[0],
+ pos[1],
+ pos[2],
+ pos[3],
+ pos[4],
+ pos[5],
+ self.lineWidth,
+ mouseX,
+ mouseY,
+ );
+ }
+ }
+ return false;
+ });
+ }
+ function Edge(source, target, label) {
+ (this.initialize = function () {
+ Edge.prototype.initialize.apply(this, arguments);
+ }),
+ this.initialize(source, target, label),
+ (this.paint = function (ctx, needHideText) {
+ if (this.drawLine && typeof this.drawLine === "function") {
+ this.drawLine(ctx);
+ return false;
+ }
+ if (null != this.source && null != this.target) {
+ if (this.colorType == "source") {
+ this.strokeColor = this.source.fillColor;
+ } else if (
+ this.colorType == "target" ||
+ this.colorType == "both"
+ ) {
+ this.strokeColor = this.target.fillColor;
+ }
+ this.groupNum = calLineNum(this.target, this.source, true);
+ if (this.source === this.target || this.groupNum > 1) {
+ if (this.source === this.target) {
+ this.lineType = "curver";
+ } else {
+ this.paintMutilPath(ctx, !needHideText);
+ return;
+ }
+ }
+ this.paintLine(ctx, label);
+ }
+ });
+ (this.paintLine = function (ctx, label) {
+ var lineType = this.lineType;
+ switch (lineType) {
+ case "direct":
+ this.paintDrirectLine(ctx, label);
+ break;
+ case "curver":
+ this.paintCurverLink(ctx, label);
+ break;
+ case "vlink":
+ this.paintVerticalLink(ctx, label);
+ break;
+ case "hlink":
+ this.paintHorizolLink(ctx, label);
+ break;
+ case "bezier":
+ this.paintBezier(ctx, label);
+ break;
+ case "vbezier":
+ this.paintVBezierLink(ctx, label);
+ break;
+ case "hbezier":
+ this.paintHBezierLink(ctx, label);
+ break;
+ case "arrowline":
+ this.paintArrowLine(ctx, label);
+ break;
+ case "minderline":
+ this.paintXMinderLine(ctx, label);
+ break;
+ case "gephiline":
+ this.paintGephiLine(ctx, label);
+ break;
+ default:
+ this.lineType == "direct";
+ this.paintDrirectLine(ctx, label);
+ break;
+ }
+ }),
+ (this.paintAnimateBall = function (ctx) {
+ var self = this;
+ var path = self.path;
+ if (path.length == 2) {
+ self.animateBallIndex = 1;
+ }
+ if (
+ self.animateBallIndex > 0 &&
+ self.animateBallIndex < path.length
+ ) {
+ var sx = path[self.animateBallIndex - 1].x,
+ sy = path[self.animateBallIndex - 1].y,
+ tx = path[self.animateBallIndex].x,
+ ty = path[self.animateBallIndex].y;
+ var angle = Math.atan2(ty - sy, tx - sx);
+ var animateBall = self.animateBall;
+ if (
+ animateBall == null ||
+ animateBall.sx != sx ||
+ animateBall.sy != sy ||
+ animateBall.tx != tx ||
+ animateBall.ty != ty
+ ) {
+ var dx = tx - sx,
+ dy = ty - sy;
+ var diff = Math.sqrt(dx * dx + dy * dy);
+ var moves = diff / self.animateSpeed;
+ self.animateBall = {
+ x: sx,
+ y: sy,
+ sx: sx,
+ sy: sy,
+ tx: tx,
+ ty: ty,
+ angle: angle,
+ moves: moves,
+ };
+ }
+ } else {
+ self.animateBallIndex = 0;
+ self.animateBall = null;
+ }
+ if (self.animateBall && self.animateBall.moves > 0) {
+ self.animateBall.moves--;
+ self.animateBall.x +=
+ self.animateSpeed * Math.cos(self.animateBall.angle);
+ self.animateBall.y +=
+ self.animateSpeed * Math.sin(self.animateBall.angle);
+ ctx.save();
+ ctx.beginPath();
+ ctx.fillStyle = `rgba(${self.animateBallColor},${self.alpha})`;
+ ctx.arc(
+ self.animateBall.x,
+ self.animateBall.y,
+ self.animateBallSize,
+ 0,
+ 2 * Math.PI,
+ );
+ ctx.fill();
+ ctx.closePath();
+ ctx.restore();
+ if (self.animateBall.moves <= 0) {
+ self.animateBall = null;
+ self.animateBallIndex++;
+ }
+ } else {
+ self.animateBallIndex++;
+ }
+ }),
+ (this.setLineStyle = function (ctx) {
+ ctx.lineJoin = "round";
+ ctx.lineCap = "round";
+ if (this.selected || this.showSelected) {
+ ctx.strokeStyle = `rgba(${this.selectedColor},${this.selectedAlpha})`;
+ ctx.lineWidth = this.lineWidth + 2;
+ } else {
+ if (this.colorType == "both") {
+ var grd = ctx.createLinearGradient(
+ this.source.cx,
+ this.source.cy,
+ this.target.cx,
+ this.target.cy,
+ );
+ if (this.source.fillColor) {
+ grd.addColorStop(
+ 0,
+ `rgba(${this.source.fillColor},${this.alpha || 0.8})`,
+ );
+ }
+ if (this.target.fillColor) {
+ grd.addColorStop(
+ 1,
+ `rgba(${this.target.fillColor},${this.alpha || 0.8})`,
+ );
+ }
+ ctx.strokeStyle = grd;
+ } else {
+ ctx.strokeStyle = `rgba(${this.strokeColor},${this.alpha || 0.8})`;
+ }
+ ctx.lineWidth = this.lineWidth;
+ }
+ if (this.lineDash && this.lineDash.length > 1) {
+ ctx.setLineDash(this.lineDash);
+ if (this.animate) {
+ ctx.lineDashOffset = this.lineDashOffset -= 2;
+ this.lineDashOffset =
+ this.lineDashOffset < -100 ? 1 : this.lineDashOffset;
+ }
+ }
+ }),
+ (this.paintMutilPath = function (ctx, showText) {
+ var start = { x: this.source.cx, y: this.source.cy },
+ end = { x: this.target.cx, y: this.target.cy };
+ var controlPoints = this.computeControlPoint(start, end);
+ var lineS = controlPoints.startPoint;
+ var lineE = controlPoints.endPoint;
+ var angle = Math.atan2(lineE.y - end.y, lineE.x - end.x);
+ var insertPoint = end;
+ var endPoint = end;
+ if (this.showArrow) {
+ if (this.target.shape == "rect") {
+ insertPoint = this.findInsertPoint(this.target, {
+ cx: lineE.x,
+ cy: lineE.y,
+ });
+ } else {
+ var radius =
+ (this.target.radius + this.target.borderWidth / 2) *
+ this.target.scaleX;
+ insertPoint = DGraph.util.pointOnCircle(
+ end.x,
+ end.y,
+ radius,
+ angle,
+ );
+ }
+ if (insertPoint == null) {
+ insertPoint = end;
+ }
+ var arrowSize = this.getArrowRadius();
+ (endPoint.x = insertPoint.x + arrowSize * Math.cos(angle)),
+ (endPoint.y = insertPoint.y + arrowSize * Math.sin(angle));
+ }
+ this.path = [];
+ this.path.push({ x: start.x, y: start.y }),
+ this.path.push({ x: lineS.x, y: lineS.y }),
+ this.path.push({ x: lineE.x, y: lineE.y }),
+ this.path.push({ x: insertPoint.x, y: insertPoint.y });
+ this.paintLineBackGround(ctx);
+ ctx.save();
+ ctx.beginPath();
+ ctx.moveTo(this.path[0].x, this.path[0].y);
+ for (var j = 1; j < this.path.length - 1; j++) {
+ ctx.lineTo(this.path[j].x, this.path[j].y);
+ }
+ ctx.lineTo(endPoint.x, endPoint.y);
+ this.setLineStyle(ctx), ctx.stroke(), ctx.restore();
+ if (this.showArrow) {
+ this.paintSpecialArrow(
+ ctx,
+ { x: lineE.x, y: lineE.y },
+ insertPoint,
+ );
+ }
+ if (
+ this.animate &&
+ (this.lineDash == null || this.lineDash.length <= 1)
+ ) {
+ this.paintAnimateBall(ctx);
+ }
+ if (this.showlabel && showText) {
+ this.paintTextOnLineWithAngle(
+ ctx,
+ { cx: lineS.x, cy: lineS.y },
+ { cx: lineE.x, cy: lineE.y },
+ );
+ }
+ }),
+ (this.computeControlPoint = function (start, end) {
+ this.bundleOffset = DGraph.util.getDistance(start, end) * 0.45;
+ var lineNum = this.groupNum;
+ var angle = Math.atan2(end.y - start.y, end.x - start.x),
+ gsPoint = {
+ x: start.x + this.bundleOffset * Math.cos(angle),
+ y: start.y + this.bundleOffset * Math.sin(angle),
+ },
+ gtPoint = {
+ x: end.x + this.bundleOffset * Math.cos(angle - Math.PI),
+ y: end.y + this.bundleOffset * Math.sin(angle - Math.PI),
+ },
+ bundleGap = (lineNum * this.bundleGap) / 2 - this.bundleGap / 2,
+ offset = this.bundleGap * this.nodeIndex;
+ angle -= Math.PI / 2;
+ var lineS = {
+ x:
+ gsPoint.x +
+ offset * Math.cos(angle) +
+ bundleGap * Math.cos(angle - Math.PI),
+ y:
+ gsPoint.y +
+ offset * Math.sin(angle) +
+ bundleGap * Math.sin(angle - Math.PI),
+ },
+ lineE = {
+ x:
+ gtPoint.x +
+ offset * Math.cos(angle) +
+ bundleGap * Math.cos(angle - Math.PI),
+ y:
+ gtPoint.y +
+ offset * Math.sin(angle) +
+ bundleGap * Math.sin(angle - Math.PI),
+ };
+ return { startPoint: lineS, endPoint: lineE };
+ }),
+ (this.paintCurverLink = function (ctx) {
+ var source = this.source,
+ target = this.target;
+ var sX = source.cx,
+ sY = source.cy;
+ var tX = this.target.cx,
+ tY = this.target.cy;
+ var dX = tX - sX,
+ dY = tY - sY,
+ sign = sX < tX ? 1 : -1,
+ cp = {},
+ c = {},
+ angle = 0,
+ t = 0.5;
+ if (source.id === target.id) {
+ var sSize = (source.radius / 2) * source.scaleX || 20;
+ this.showArrow = false;
+ cp = DGraph.util.getSelfLoopControlPoints(
+ sX,
+ sY,
+ sSize + (this.nodeIndex * this.bundleGap) / 2,
+ );
+ c = DGraph.util.getPointOnBezierCurve(
+ t,
+ sX,
+ sY,
+ tX,
+ tY,
+ cp.x1,
+ cp.y1,
+ cp.x2,
+ cp.y2,
+ );
+ angle = Math.atan2(1, 1);
+ this.path = [];
+ this.bezierPoints = [sX, sY, cp.x1, cp.y1, cp.x2, cp.y2, tX, tY];
+ } else {
+ cp = DGraph.util.getQuadraticControlPoint(
+ sX,
+ sY,
+ tX,
+ tY,
+ 4,
+ this.curveness,
+ );
+ c = DGraph.util.getPointOnQuadraticCurve(
+ t,
+ sX,
+ sY,
+ tX,
+ tY,
+ cp.x,
+ cp.y,
+ );
+ angle = Math.atan2(dY * sign, dX * sign);
+ this.path = [];
+ this.quadraticPoints = [sX, sY, cp.x, cp.y, tX, tY];
+ }
+ if (this.background) {
+ ctx.save();
+ ctx.beginPath();
+ ctx.strokeStyle = `rgba(${this.background},${this.alpha})`;
+ ctx.lineWidth = this.lineWidth * 3;
+ ctx.moveTo(sX, sY);
+ if (source.id === target.id) {
+ ctx.bezierCurveTo(cp.x1, cp.y1, cp.x2, cp.y2, tX, tY);
+ } else {
+ ctx.quadraticCurveTo(cp.x, cp.y, tX, tY);
+ }
+ ctx.stroke();
+ ctx.restore();
+ }
+ ctx.beginPath();
+ ctx.moveTo(sX, sY);
+ this.setLineStyle(ctx);
+ if (source.id === target.id) {
+ ctx.bezierCurveTo(cp.x1, cp.y1, cp.x2, cp.y2, tX, tY);
+ this.animate = false;
+ } else {
+ ctx.quadraticCurveTo(cp.x, cp.y, tX, tY);
+ }
+ ctx.stroke();
+ if (
+ this.animate &&
+ (this.lineDash == null || this.lineDash.length <= 1)
+ ) {
+ this.paintCurverAnimate(ctx, sX, sY, tX, tY, cp.x, cp.y);
+ }
+ if (this.showArrow) {
+ var pos1 = DGraph.util.getPointOnQuadraticCurve(
+ 0.5,
+ sX,
+ sY,
+ tX,
+ tY,
+ cp.x,
+ cp.y,
+ );
+ var pos2 = DGraph.util.getPointOnQuadraticCurve(
+ 0.52,
+ sX,
+ sY,
+ tX,
+ tY,
+ cp.x,
+ cp.y,
+ );
+ this.paintSpecialArrow(
+ ctx,
+ { x: pos1.x, y: pos1.y },
+ { x: pos2.x, y: pos2.y },
+ );
+ }
+ this.paintLineText(ctx, c.x, c.y, angle);
+ this.paintLineTips(ctx, { x: c.x, y: c.y });
+ }),
+ (this.paintCurverAnimate = function (ctx, sx, sy, tx, ty, cpx, cpy) {
+ var self = this;
+ if (self.animateBall && self.animateBall.moves < 1) {
+ self.animateBall.moves += 0.02;
+ var pos = DGraph.util.getPointOnQuadraticCurve(
+ self.animateBall.moves,
+ sx,
+ sy,
+ tx,
+ ty,
+ cpx,
+ cpy,
+ );
+ ctx.save();
+ ctx.beginPath();
+ ctx.fillStyle = `rgba(${self.animateBallColor},${self.alpha})`;
+ ctx.arc(pos.x, pos.y, self.animateBallSize, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.closePath();
+ ctx.restore();
+ } else {
+ self.animateBall = { moves: 0 };
+ }
+ }),
+ (this.paintArrowLine = function (ctx, b) {
+ var width = this.lineWidth;
+ width = width < 4 ? 4 : width;
+ var pos = { x: this.target.cx, y: this.target.cy };
+ if (this.showArrow) {
+ pos = this.calculateEndPoint(this.source, this.target);
+ }
+ var x0 = this.source.cx;
+ var y0 = this.source.cy;
+ var x1 = pos.x;
+ var y1 = pos.y;
+ if (this.reverse) {
+ x0 = pos.x;
+ y0 = pos.y;
+ x1 = this.source.cx;
+ y1 = this.source.cy;
+ }
+ ctx.save();
+ ctx.beginPath();
+ if (this.showArrow) {
+ ctx.arrow(x0, y0, x1, y1, [
+ -3 * width,
+ width,
+ -4 * width,
+ 3 * width + 1,
+ ]);
+ } else {
+ ctx.arrow(x0, y0, x1, y1, [0, width]);
+ }
+ ctx.lineJoin = "round";
+ if (this.colorType == "both") {
+ var grd = ctx.createLinearGradient(
+ this.source.cx,
+ this.source.cy,
+ this.target.cx,
+ this.target.cy,
+ );
+ grd.addColorStop(
+ 0,
+ `rgba(${this.source.fillColor},${this.alpha})`,
+ );
+ grd.addColorStop(
+ 1,
+ `rgba(${this.target.fillColor},${this.alpha})`,
+ );
+ ctx.fillStyle = grd;
+ } else {
+ ctx.fillStyle = `rgba(${this.strokeColor},${this.alpha})`;
+ }
+ if (this.selected || this.showSelected) {
+ ctx.fillStyle = `rgba(${this.selectedColor},${this.selectedAlpha})`;
+ }
+ ctx.fill();
+ ctx.restore();
+ this.path = [
+ { x: x0, y: y0 },
+ { x: x1, y: y1 },
+ ];
+ this.paintTextOnLineWithAngle(ctx, this.source, this.target);
+ }),
+ (this.paintXMinderLine = function (cxt, b) {
+ var source = this.source,
+ target = this.target;
+ var sourceX = source.cx,
+ sourceY = source.cy;
+ var targetX = target.cx,
+ targetY = target.cy;
+ if (sourceX > targetX) {
+ targetX = target.x + target.width / 2;
+ } else if (sourceX < targetX) {
+ targetX = target.x;
+ }
+ cxt.beginPath();
+ this.setLineStyle(cxt);
+ cxt.moveTo(source.cx, source.cy);
+ cxt.lineTo((sourceX + targetX) / 2, sourceY);
+ cxt.lineTo((sourceX + targetX) / 2, targetY);
+ cxt.lineTo(target.cx, target.cy);
+ cxt.stroke();
+ this.path = [
+ { x: sourceX, y: sourceY },
+ { x: (sourceX + targetX) / 2, y: sourceY },
+ { x: (sourceX + targetX) / 2, y: targetY },
+ { x: targetX, y: targetY },
+ ];
+ }),
+ (this.calculateEndPoint = function (source, target) {
+ var angle = 0;
+ this.arrowsRadius = this.getArrowRadius();
+ var offset = 0,
+ posX = target.cx,
+ posY = target.cy;
+ if ("rect" == this.target.shape) {
+ var cod = this.getPath();
+ posX = cod[1].x;
+ posY = cod[1].y;
+ angle = Math.atan2(posY - cod[0].y, posX - cod[0].x);
+ } else {
+ var startPoint = { x: source.cx, y: source.cy },
+ endPoint = { x: target.cx, y: target.cy };
+ offset = -(
+ (target.radius + target.borderWidth / 2) *
+ target.scaleX
+ );
+ (angle = Math.atan2(
+ endPoint.y - startPoint.y,
+ endPoint.x - startPoint.x,
+ )),
+ (posX = endPoint.x + offset * Math.cos(angle)),
+ (posY = endPoint.y + offset * Math.sin(angle));
+ }
+ return { x: posX, y: posY, angle: angle };
+ }),
+ (this.paintDrirectLine = function (ctx) {
+ var posX = this.target.cx,
+ posY = this.target.cy;
+ var linetX = posX,
+ linetY = posY;
+ if (this.showArrow) {
+ var endPoint = this.calculateEndPoint(this.source, this.target);
+ posX = endPoint.x;
+ posY = endPoint.y;
+ linetX = posX - this.arrowsRadius * Math.cos(endPoint.angle);
+ linetY = posY - this.arrowsRadius * Math.sin(endPoint.angle);
+ }
+ this.path = [
+ { x: this.source.cx, y: this.source.cy },
+ { x: this.target.cx, y: this.target.cy },
+ ];
+ this.paintLineBackGround(ctx);
+ ctx.beginPath(), ctx.moveTo(this.source.cx, this.source.cy);
+ this.setLineStyle(ctx);
+ ctx.lineTo(linetX, linetY), ctx.stroke();
+ if (this.showArrow) {
+ var start, end;
+ if ("rect" == this.target.shape) {
+ var cod = this.getPath();
+ (start = cod[0]), (end = cod[1]);
+ } else {
+ (start = { x: this.source.cx, y: this.source.cy }),
+ (end = { x: posX, y: posY });
+ }
+ this.paintSpecialArrow(ctx, start, end);
+ }
+ if (
+ this.animate &&
+ (this.lineDash == null || this.lineDash.length <= 1)
+ ) {
+ this.paintAnimateBall(ctx);
+ }
+ this.paintTextOnLineWithAngle(ctx, this.source, this.target);
+ }),
+ (this.paintTextOnLineWithAngle = function (ctx, start, end) {
+ if (this.showlabel && this.label) {
+ let textAngle = Math.atan2(end.cy - start.cy, end.cx - start.cx);
+ if (textAngle > Math.PI / 2) textAngle = -(Math.PI - textAngle);
+ if (textAngle < -Math.PI / 2) textAngle = -(-Math.PI - textAngle);
+ let textPos = {
+ x: start.cx + (end.cx - start.cx) / 2,
+ y: start.cy + (end.cy - start.cy) / 2,
+ };
+ this.paintLineText(ctx, textPos.x, textPos.y, textAngle);
+ }
+ this.paintLineTips(ctx, {
+ x: start.cx + (end.cx - start.cx) / 2,
+ y: start.cy + (end.cy - start.cy) / 2,
+ });
+ }),
+ (this.paintLineTips = function (ctx, textPos) {
+ if (this.hideText) {
+ return false;
+ }
+ if (this.tipText) {
+ var radius = this.tipRadius || 0;
+ var padding = 12;
+ ctx.save();
+ ctx.font = this.tipFont || "normal 13px Arial";
+ var width = ctx.measureText(this.tipText).width + padding;
+ var height = ctx.measureText("田").width + padding - 2;
+ radius = radius > height / 2 ? height / 2 : radius;
+ // radius = height / 2 ;
+ ctx.translate(textPos.x - width / 2, textPos.y - height - 6);
+ ctx.beginPath();
+ ctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
+ ctx.lineTo(width / 2 + 4, height);
+ ctx.lineTo(width / 2, height + 6);
+ ctx.lineTo(width / 2 - 4, height);
+ ctx.lineTo(radius, height);
+ ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
+ ctx.lineTo(0, radius);
+ ctx.arc(radius, radius, radius, Math.PI, (Math.PI * 3) / 2);
+ ctx.lineTo(width - radius, 0);
+ ctx.arc(
+ width - radius,
+ radius,
+ radius,
+ (Math.PI * 3) / 2,
+ Math.PI * 2,
+ );
+ ctx.lineTo(width, height - radius);
+ ctx.closePath();
+ ctx.fillStyle = `rgba(${this.tipColor || "250,50,50"},${this.alpha})`;
+ ctx.fill();
+ ctx.translate(width / 2, height / 2);
+ ctx.textBaseline = "middle";
+ ctx.textAlign = "center";
+ ctx.fillStyle = `rgba(${this.tipFontColor || "250,250,250"},${this.alpha})`;
+ ctx.fillText(this.tipText, 0, 0);
+ ctx.restore();
+ }
+ }),
+ (this.getArrowRadius = function () {
+ var raduis = Math.round(3 * this.lineWidth);
+ return Math.min(Math.max(raduis, 6), 80);
+ }),
+ (this.getTargetBorderPoint = function () {
+ var radius = 0;
+ if (this.showArrow) {
+ var target = this.target;
+ radius = target.radius;
+ if ("rect" == target.shape) {
+ if (["vbezier", "vlink"].indexOf(this.lineType) != -1) {
+ radius =
+ (target.height / 2 + target.borderWidth / 2) *
+ target.scaleX;
+ } else {
+ radius =
+ (target.width / 2 + target.borderWidth / 2) * target.scaleX;
+ }
+ } else {
+ radius =
+ (target.radius + target.borderWidth / 2) * target.scaleX;
+ }
+ }
+ return radius;
+ }),
+ (this.paintTriangleArrow = function (ctx, sourceP, targetP) {
+ var arrowsRadius = this.getArrowRadius() + 2;
+ var angle = Math.atan2(
+ targetP.y - sourceP.y,
+ targetP.x - sourceP.x,
+ );
+ ctx.save();
+ ctx.translate(targetP.x, targetP.y);
+ ctx.rotate(angle + 1);
+ if (this.selected || this.showSelected) {
+ ctx.fillStyle = `rgba(${this.selectedColor},${this.selectedAlpha})`;
+ } else {
+ ctx.fillStyle = `rgba(${this.strokeColor},${this.alpha})`;
+ }
+ ctx.beginPath();
+ ctx.moveTo(0, arrowsRadius);
+ ctx.lineTo(0, 0);
+ ctx.rotate(-2);
+ ctx.lineTo(0, -arrowsRadius);
+ ctx.closePath(), ctx.fill(), ctx.restore();
+ }),
+ (this.paintSpecialArrow = function (ctx, sourceP, targetP) {
+ if (this.arrowType == "arrow") {
+ var arrowsRadius = this.getArrowRadius();
+ var angle = Math.atan(
+ (targetP.x - sourceP.x) / (targetP.y - sourceP.y),
+ );
+ ctx.save();
+ ctx.translate(targetP.x, targetP.y);
+ if (targetP.y - sourceP.y >= 0) {
+ ctx.rotate(-angle);
+ } else {
+ ctx.rotate(Math.PI - angle);
+ }
+ if (this.selected || this.showSelected) {
+ ctx.fillStyle = `rgba(${this.selectedColor},${this.selectedAlpha})`;
+ } else {
+ ctx.fillStyle = `rgba(${this.strokeColor},${this.alpha})`;
+ }
+ ctx.beginPath();
+ ctx.lineTo(-arrowsRadius, -arrowsRadius * 2);
+ ctx.lineTo(0, -arrowsRadius);
+ ctx.lineTo(arrowsRadius, -arrowsRadius * 2);
+ ctx.lineTo(0, 0);
+ ctx.closePath();
+ ctx.fill();
+ ctx.restore();
+ } else {
+ this.paintTriangleArrow(ctx, sourceP, targetP);
+ }
+ }),
+ (this.paintVerticalLink = function (cxt) {
+ var source = this.source,
+ target = this.target;
+ var sourceX = source.cx,
+ sourceY = source.cy;
+ var targetX = target.cx,
+ targetY = target.cy;
+ this.path = [
+ { x: sourceX, y: sourceY },
+ { x: sourceX, y: (sourceY + targetY) / 2 },
+ { x: targetX, y: (sourceY + targetY) / 2 },
+ { x: targetX, y: targetY },
+ ];
+ var radius = 0;
+ if (this.showArrow) {
+ radius = this.getTargetBorderPoint();
+ if (sourceY > targetY) {
+ radius = -radius;
+ }
+ }
+ this.paintLineBackGround(cxt);
+ var lastPath = this.path[this.path.length - 1];
+ cxt.beginPath();
+ this.setLineStyle(cxt);
+ cxt.moveTo(this.path[0].x, this.path[0].y);
+ for (var i = 1; i < this.path.length - 1; i++) {
+ cxt.lineTo(this.path[i].x, this.path[i].y);
+ }
+ if (sourceY >= targetY) {
+ cxt.lineTo(lastPath.x, targetY - radius + this.getArrowRadius());
+ } else {
+ cxt.lineTo(lastPath.x, targetY - radius - this.getArrowRadius());
+ }
+ cxt.stroke();
+ if (this.showArrow) {
+ this.paintSpecialArrow(
+ cxt,
+ { x: targetX, y: (sourceY + targetY) / 2 },
+ { x: targetX, y: targetY - radius },
+ );
+ }
+ if (
+ this.animate &&
+ (this.lineDash == null || this.lineDash.length <= 1)
+ ) {
+ this.paintAnimateBall(cxt);
+ }
+ this.paintLineText(
+ cxt,
+ (sourceX + targetX) / 2,
+ (targetY + sourceY) / 2,
+ );
+ this.paintLineTips(cxt, {
+ x: (sourceX + targetX) / 2,
+ y: (targetY + sourceY) / 2,
+ });
+ }),
+ (this.paintHorizolLink = function (cxt) {
+ var source = this.source,
+ target = this.target;
+ var sourceX = source.cx,
+ sourceY = source.cy;
+ var targetX = target.cx,
+ targetY = target.cy;
+ var radius = 0;
+ if (this.showArrow) {
+ radius = this.getTargetBorderPoint();
+ if (sourceX > targetX) {
+ radius = -radius;
+ }
+ }
+ this.path = [
+ { x: sourceX, y: sourceY },
+ { x: (sourceX + targetX - radius) / 2, y: sourceY },
+ { x: (sourceX + targetX - radius) / 2, y: targetY },
+ { x: targetX, y: targetY },
+ ];
+ this.paintLineBackGround(cxt);
+ var lastPath = this.path[this.path.length - 1];
+ cxt.beginPath();
+ this.setLineStyle(cxt);
+ cxt.moveTo(this.path[0].x, this.path[0].y);
+ for (var i = 1; i < this.path.length - 1; i++) {
+ cxt.lineTo(this.path[i].x, this.path[i].y);
+ }
+ if (sourceX >= targetX) {
+ cxt.lineTo(targetX - radius + this.getArrowRadius(), lastPath.y);
+ } else {
+ cxt.lineTo(targetX - radius - this.getArrowRadius(), lastPath.y);
+ }
+ cxt.stroke();
+ if (this.showArrow) {
+ this.paintSpecialArrow(
+ cxt,
+ { x: (sourceX + targetX) / 2, y: targetY },
+ { x: targetX - radius, y: targetY },
+ );
+ }
+ if (
+ this.animate &&
+ (this.lineDash == null || this.lineDash.length <= 1)
+ ) {
+ this.paintAnimateBall(cxt);
+ }
+ this.paintLineText(
+ cxt,
+ (sourceX + targetX) / 2,
+ (targetY + sourceY) / 2,
+ );
+ this.paintLineTips(cxt, {
+ x: (sourceX + targetX) / 2,
+ y: (targetY + sourceY) / 2,
+ });
+ }),
+ (this.paintLineBackGround = function (ctx) {
+ if (this.background) {
+ ctx.save();
+ ctx.beginPath(), (ctx.lineCap = "round");
+ ctx.lineJoin = "round";
+ ctx.moveTo(this.path[0].x, this.path[0].y);
+ for (var i = 1; i < this.path.length; i++) {
+ ctx.lineTo(this.path[i].x, this.path[i].y);
+ }
+ ctx.strokeStyle = `rgba(${this.background},${this.alpha})`;
+ ctx.lineWidth = (this.lineWidth + 2) * 3;
+ ctx.stroke(), ctx.restore();
+ }
+ }),
+ (this.paintBezier = function (cxt) {
+ var angle = DGraph.util.calculateAngle(
+ this.source.cx,
+ this.source.cy,
+ this.target.cx,
+ this.target.cy,
+ );
+ if (
+ (angle >= 0 && angle <= 45) ||
+ (angle >= 135 && angle <= 225) ||
+ (angle >= 315 && angle <= 360)
+ ) {
+ this.paintVBezierLink(cxt);
+ } else {
+ this.paintHBezierLink(cxt);
+ }
+ }),
+ (this.paintHBezierLink = function (cxt) {
+ var source = this.source,
+ target = this.target;
+ var sourceX = source.cx,
+ sourceY = source.cy;
+ var targetX = target.cx,
+ targetY = target.cy;
+ var radius = 0,
+ arrowRadius = this.getArrowRadius();
+ if (this.showArrow) {
+ targetX =
+ target.cx -
+ (target.width / 2 + target.borderWidth / 2) * target.scaleX -
+ arrowRadius;
+ radius = this.getTargetBorderPoint();
+ if (sourceX > target.cx) {
+ targetX =
+ target.cx +
+ (target.width / 2 + target.borderWidth / 2) * target.scaleX +
+ arrowRadius;
+ radius = -radius;
+ }
+ }
+ var x3 = (sourceX + targetX) * this.curveness,
+ y3 = sourceY,
+ x4 = (sourceX + targetX) * this.curveness,
+ y4 = targetY;
+ if (this.background) {
+ cxt.save();
+ cxt.beginPath();
+ cxt.strokeStyle = `rgba(${this.background},${this.alpha})`;
+ cxt.lineWidth = this.lineWidth * 3;
+ cxt.moveTo(sourceX, sourceY);
+ cxt.bezierCurveTo(x3, y3, x4, y4, targetX, targetY);
+ cxt.lineTo(target.cx, target.cy);
+ cxt.stroke();
+ cxt.restore();
+ }
+ cxt.beginPath();
+ this.setLineStyle(cxt);
+ cxt.moveTo(sourceX, sourceY);
+ cxt.bezierCurveTo(x3, y3, x4, y4, targetX, targetY);
+ cxt.stroke();
+ this.path = [];
+ this.bezierPoints = [
+ sourceX,
+ sourceY,
+ x3,
+ y3,
+ x4,
+ y4,
+ targetX,
+ targetY,
+ ];
+ if (this.showArrow) {
+ this.paintSpecialArrow(
+ cxt,
+ { x: targetX, y: targetY },
+ { x: target.cx - radius, y: target.cy },
+ );
+ }
+ if (
+ this.animate &&
+ (this.lineDash == null || this.lineDash.length <= 1)
+ ) {
+ this.paintBezierAnimate(
+ cxt,
+ source.cx,
+ source.cy,
+ targetX,
+ targetY,
+ x3,
+ y3,
+ x4,
+ y4,
+ );
+ }
+ this.paintBezierText(
+ cxt,
+ source.cx,
+ source.cy,
+ targetX,
+ targetY,
+ x3,
+ y3,
+ x4,
+ y4,
+ );
+ }),
+ (this.paintVBezierLink = function (cxt) {
+ var source = this.source,
+ target = this.target;
+ var sourceX = source.cx,
+ sourceY = source.cy;
+ var targetX = target.cx,
+ targetY = target.cy;
+ var radius = 0;
+ if (this.showArrow) {
+ targetY =
+ target.cy -
+ (target.height / 2 + target.borderWidth / 2) * target.scaleX -
+ this.getArrowRadius();
+ radius = this.getTargetBorderPoint();
+ if (sourceY > target.cy) {
+ targetY =
+ target.cy +
+ (target.height / 2 + target.borderWidth / 2) * target.scaleX +
+ this.getArrowRadius();
+ radius = -radius;
+ }
+ }
+ var x3 = sourceX;
+ var y3 = (sourceY + targetY) * this.curveness;
+ var x4 = targetX;
+ var y4 = (sourceY + targetY) * this.curveness;
+ if (this.background) {
+ cxt.save();
+ cxt.beginPath();
+ cxt.strokeStyle = `rgba(${this.background},${this.alpha})`;
+ cxt.lineWidth = this.lineWidth * 3;
+ cxt.moveTo(source.cx, source.cy);
+ cxt.bezierCurveTo(x3, y3, x4, y4, targetX, targetY);
+ cxt.lineTo(targetX, target.cy);
+ cxt.stroke();
+ cxt.restore();
+ }
+ cxt.beginPath();
+ this.setLineStyle(cxt);
+ cxt.moveTo(source.cx, source.cy);
+ cxt.bezierCurveTo(x3, y3, x4, y4, targetX, targetY);
+ cxt.stroke();
+ this.path = [];
+ this.bezierPoints = [
+ source.cx,
+ source.cy,
+ x3,
+ y3,
+ x4,
+ y4,
+ targetX,
+ targetY,
+ ];
+ if (this.showArrow) {
+ this.paintSpecialArrow(
+ cxt,
+ { x: targetX, y: targetY },
+ { x: target.cx, y: target.cy - radius },
+ );
+ }
+ this.paintBezierText(
+ cxt,
+ source.cx,
+ source.cy,
+ targetX,
+ targetY,
+ x3,
+ y3,
+ x4,
+ y4,
+ );
+ if (
+ this.animate &&
+ (this.lineDash == null || this.lineDash.length <= 1)
+ ) {
+ this.paintBezierAnimate(
+ cxt,
+ source.cx,
+ source.cy,
+ targetX,
+ targetY,
+ x3,
+ y3,
+ x4,
+ y4,
+ );
+ }
+ }),
+ (this.paintBezierAnimate = function (
+ ctx,
+ sx,
+ sy,
+ tx,
+ ty,
+ cpx1,
+ cpy1,
+ cpx2,
+ cpy2,
+ ) {
+ var self = this;
+ if (self.animateBall && self.animateBall.moves < 1) {
+ self.animateBall.moves += 0.02;
+ var pos = DGraph.util.getPointOnBezierCurve(
+ self.animateBall.moves,
+ sx,
+ sy,
+ tx,
+ ty,
+ cpx1,
+ cpy1,
+ cpx2,
+ cpy2,
+ );
+ ctx.save();
+ ctx.beginPath();
+ ctx.arc(pos.x, pos.y, self.animateBallSize, 0, 2 * Math.PI);
+ ctx.closePath();
+ ctx.fillStyle = `rgba(${self.animateBallColor},${self.alpha})`;
+ ctx.fill();
+ ctx.restore();
+ } else {
+ self.animateBall = { moves: 0 };
+ }
+ }),
+ (this.paintBezierText = function (
+ cxt,
+ sx,
+ sy,
+ tx,
+ ty,
+ cpx1,
+ cpy1,
+ cpx2,
+ cpy2,
+ ) {
+ if (this.showlabel && this.label) {
+ var middle = DGraph.util.getPointOnBezierCurve(
+ 0.5,
+ sx,
+ sy,
+ tx,
+ ty,
+ cpx1,
+ cpy1,
+ cpx2,
+ cpy2,
+ );
+ if (["gephiline", "curver"].indexOf(this.lineType) > -1) {
+ var sign = cpx2 - cpx1 > 0 ? -1 : 1;
+ var angle =
+ Math.atan2((cpx2 - cpx1) * sign, (cpy2 - cpy1) * -sign) +
+ Math.PI / 2;
+ this.paintLineText(cxt, middle.x, middle.y, angle);
+ } else {
+ this.paintLineText(cxt, middle.x, middle.y);
+ }
+ this.paintLineTips(cxt, { x: middle.x, y: middle.y });
+ } else {
+ if (this.tipText) {
+ var middle = DGraph.util.getPointOnBezierCurve(
+ 0.5,
+ sx,
+ sy,
+ tx,
+ ty,
+ cpx1,
+ cpy1,
+ cpx2,
+ cpy2,
+ );
+ this.paintLineTips(cxt, { x: middle.x, y: middle.y });
+ }
+ }
+ }),
+ (this.paintLineText = function (cxt, posX, posY, angle) {
+ if (!this.showlabel || !this.label || this.hideText) {
+ return false;
+ }
+ var baseLine = "bottom";
+ if (this.tipText) {
+ baseLine = "top";
+ }
+ if (this.labelBackGround) {
+ var textPadding = 4;
+ baseLine = "middle";
+ cxt.save();
+ cxt.font = this.font;
+ var textWidth =
+ cxt.measureText(this.label).width + textPadding * 2;
+ var textHeight = cxt.measureText("田").width + textPadding;
+ this.labelBackHeight = textHeight;
+ cxt.translate(posX, posY);
+ cxt.rotate(angle ? angle : 0);
+ cxt.lineWidth = 1;
+ cxt.strokeStyle = `rgba(${this.labelBorderColor},${this.alpha})`;
+ cxt.fillStyle = `rgba(${this.labelBackGround},${this.alpha})`;
+ cxt.DGraphRoundRect(
+ -textWidth / 2,
+ -textHeight / 2 - 1,
+ textWidth,
+ textHeight,
+ textHeight / 2 - textPadding,
+ );
+ cxt.fill(), cxt.stroke(), cxt.restore();
+ }
+ cxt.save();
+ cxt.font = this.font;
+ cxt.translate(posX, posY);
+ cxt.rotate(angle ? angle : 0);
+ cxt.textAlign = "center";
+ cxt.textBaseline = baseLine;
+ cxt.fillStyle = `rgba(${this.fontColor},${this.alpha})`;
+ cxt.fillText(this.label, 0, 0);
+ cxt.restore();
+ }),
+ (this.paintGephiLine = function (ctx, label) {
+ var self = this;
+ var source = {
+ x: self.source.cx,
+ y: self.source.cy,
+ r: self.width,
+ };
+ var target = {
+ x: self.target.cx,
+ y: self.target.cy,
+ r: self.width,
+ };
+ var arrow_size = self.lineWidth * 3.5;
+ var x2, y2, x3, y3, x4, y4, x5, y5;
+ x2 = source.x;
+ y2 = source.y;
+ x3 =
+ 0.3 * target.y - 0.3 * source.y + 0.8 * source.x + 0.2 * target.x;
+ y3 =
+ 0.8 * source.y + 0.2 * target.y - 0.3 * target.x + 0.3 * source.x;
+ x4 =
+ 0.3 * target.y - 0.3 * source.y + 0.2 * source.x + 0.8 * target.x;
+ y4 =
+ 0.2 * source.y + 0.8 * target.y - 0.3 * target.x + 0.3 * source.x;
+ x5 = target.x;
+ y5 = target.y;
+ if (this.background) {
+ ctx.save();
+ ctx.beginPath();
+ ctx.strokeStyle = `rgba(${this.background},${this.alpha})`;
+ ctx.lineWidth = this.lineWidth * 3;
+ ctx.moveTo(x2, y2);
+ ctx.bezierCurveTo(x3, y3, x4, y4, x5, y5);
+ ctx.stroke();
+ ctx.restore();
+ }
+ ctx.beginPath();
+ ctx.moveTo(x2, y2);
+ this.setLineStyle(ctx);
+ ctx.bezierCurveTo(x3, y3, x4, y4, x5, y5);
+ ctx.stroke();
+ this.path = [];
+ this.bezierPoints = [x2, y2, x3, y3, x4, y4, x5, y5];
+ if (
+ this.animate &&
+ (this.lineDash == null || this.lineDash.length <= 1)
+ ) {
+ this.paintBezierAnimate(ctx, x2, y2, x5, y5, x3, y3, x4, y4);
+ }
+ if (self.showArrow) {
+ var pos1 = DGraph.util.getPointOnBezierCurve(
+ 0.5,
+ x2,
+ y2,
+ x5,
+ y5,
+ x3,
+ y3,
+ x4,
+ y4,
+ );
+ var pos2 = DGraph.util.getPointOnBezierCurve(
+ 0.52,
+ x2,
+ y2,
+ x5,
+ y5,
+ x3,
+ y3,
+ x4,
+ y4,
+ );
+ this.paintSpecialArrow(ctx, pos1, pos2);
+ }
+ this.paintBezierText(ctx, x2, y2, x5, y5, x3, y3, x4, y4);
+ });
+ }
+ (Link.prototype = new DGraph.InteractiveElement()),
+ (DGraph.Link = Link),
+ (Edge.prototype = new Link()),
+ (DGraph.Edge = Edge);
+ })(DGraph),
+ (function (DGraph) {
+ function Group(label, fixed = false) {
+ (this.initialize = function (label, fixed = false) {
+ Group.prototype.initialize.apply(this, arguments),
+ (this.elementType = "group"),
+ (this.zIndex = DGraph.Group_zIndex),
+ (this.fixed = fixed),
+ (this.width = 100),
+ (this.height = 100),
+ (this.childs = []),
+ (this.alpha = 1),
+ (this.dragable = true),
+ (this.childDragable = true),
+ (this.visible = true),
+ (this.fillColor = "250,250,250"),
+ (this.borderWidth = 1),
+ (this.borderColor = "100,100,220"),
+ (this.selectedBorderWidth = 2),
+ (this.selectedBorderColor = "30,30,250"),
+ (this.showHeader = true),
+ (this.label = label),
+ (this.textAlign = "center"),
+ (this.textOffsetX = 6);
+ (this.font = "normal 14px Arial"),
+ (this.fontColor = "255,255,255"),
+ (this.headerColor = "60,60,200"),
+ (this.headerAlpha = 1),
+ (this.headerHeight = 36),
+ (this.padding = 20);
+ }),
+ this.initialize(label, fixed),
+ (this.add = function (nodes) {
+ var self = this;
+ if (nodes instanceof Array) {
+ nodes.forEach((node) => {
+ self.childs.push(node);
+ node.parentContainer = this;
+ });
+ } else {
+ self.childs.push(nodes);
+ nodes.parentContainer = this;
+ }
+ }),
+ (this.remove = function (node) {
+ for (var i = 0; i < this.childs.length; i++) {
+ if (this.childs[i] === node) {
+ node.dragable = true;
+ node.parentContainer = null;
+ this.childs = DGraph.util.removeFromArray(
+ this.childs,
+ this.childs[i],
+ );
+ break;
+ }
+ }
+ }),
+ (this.removeAll = function () {
+ this.childs.forEach((child) => {
+ child.dragable = true;
+ child.parentContainer = null;
+ });
+ this.childs = [];
+ }),
+ (this.setLocation = function (x, y) {
+ var offsetX = x - this.x,
+ offsetY = y - this.y;
+ (this.x = x), (this.y = y);
+ for (var i = 0; i < this.childs.length; i++) {
+ var node = this.childs[i];
+ node.setLocation(node.x + offsetX, node.y + offsetY);
+ }
+ }),
+ (this.paint = function (ctx) {
+ if (this.visible) {
+ if (!this.fixed) {
+ this.ajustSize();
+ }
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(this.x, this.y, this.width, this.height);
+ ctx.closePath(),
+ (ctx.fillStyle = `rgba(${this.fillColor},${this.alpha})`),
+ ctx.fill();
+ if (
+ !this.showSelected &&
+ !this.selected &&
+ this.borderWidth > 0
+ ) {
+ ctx.lineWidth = this.borderWidth;
+ ctx.strokeStyle = `rgba(${this.borderColor},${this.alpha})`;
+ ctx.stroke();
+ }
+ if (
+ (this.showSelected || this.selected) &&
+ this.selectedBorderWidth > 0
+ ) {
+ ctx.lineWidth = this.selectedBorderWidth;
+ ctx.strokeStyle = `rgba(${this.selectedBorderColor},${this.alpha})`;
+ ctx.stroke();
+ }
+ ctx.restore();
+ if (this.showHeader) {
+ this.paintHeader(ctx);
+ this.paintText(ctx);
+ }
+ }
+ }),
+ (this.paintHeader = function (ctx) {
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(this.x, this.y, this.width, this.headerHeight);
+ ctx.closePath();
+ (ctx.fillStyle = `rgba(${this.headerColor},${this.headerAlpha})`),
+ ctx.fill();
+ var lineWidth = this.borderWidth;
+ if (this.showSelected || this.selected) {
+ lineWidth = this.selectedBorderWidth;
+ }
+ if (lineWidth > 0) {
+ ctx.lineWidth = lineWidth;
+ (ctx.strokeStyle = `rgba(${this.headerColor},${this.headerAlpha})`),
+ ctx.stroke();
+ }
+ ctx.restore();
+ }),
+ (this.paintText = function (ctx) {
+ if (this.label) {
+ ctx.save();
+ ctx.font = this.font;
+ var textWidth = ctx.measureText(this.label).width;
+ var pos = this.getTextPostion(textWidth);
+ ctx.textBaseline = "middle";
+ ctx.fillStyle = `rgba(${this.fontColor},${this.headerAlpha})`;
+ ctx.fillText(this.label, pos.x, pos.y);
+ ctx.restore();
+ }
+ }),
+ (this.getTextPostion = function (textWidth) {
+ var position = null;
+ switch (this.textAlign) {
+ case "center":
+ position = {
+ x: this.x + this.width / 2 - textWidth / 2,
+ y: this.y + this.headerHeight / 2,
+ };
+ break;
+ case "right":
+ position = {
+ x: this.x + this.width - textWidth - this.textOffsetX,
+ y: this.y + this.headerHeight / 2,
+ };
+ break;
+ default:
+ position = {
+ x: this.x + this.textOffsetX,
+ y: this.y + this.headerHeight / 2,
+ };
+ break;
+ }
+ return position;
+ }),
+ (this.paintMouseover = function (ctx) {
+ this.showSelected = true;
+ }),
+ (this.isInBound = function (x, y) {
+ return (
+ x > this.x &&
+ x < this.x + this.width &&
+ y > this.y &&
+ y < this.y + this.height
+ );
+ }),
+ (this.ajustSize = function () {
+ var self = this;
+ var nodeCount = self.childs.length;
+ if (nodeCount > 0) {
+ var left = 1e7,
+ right = -1e7,
+ top = 1e7,
+ bottom = -1e7,
+ width = right - left,
+ height = bottom - top;
+ for (var i = 0; i < nodeCount; i++) {
+ var node = self.childs[i];
+ node.dragable = self.childDragable;
+ var scaleX = node.scaleX == 1 ? 0 : node.scaleX;
+ var scaleY = node.scaleY == 1 ? 0 : node.scaleY;
+ node.x <= left && (left = node.x - (node.width * scaleX) / 2),
+ node.x >= right && (right = node.x),
+ node.y <= top && (top = node.y - (node.height * scaleY) / 2),
+ node.y >= bottom && (bottom = node.y),
+ (width = right - left + node.width * node.scaleX),
+ (height = bottom - top + node.height * node.scaleY);
+ }
+ self.x = left - self.padding;
+ self.y = top - self.padding - self.headerHeight;
+ self.width = Math.max(width, 60) + self.padding * 2;
+ self.height =
+ Math.max(height, 60) + self.padding * 2 + self.headerHeight;
+ }
+ });
+ }
+ (Group.prototype = new DGraph.InteractiveElement()),
+ (DGraph.Group = Group);
+ })(DGraph),
+ (function (DGraph) {
+ function ColorUtils() {
+ function hexToRgb(hex) {
+ var h = hex.replace("#", "");
+ return [
+ parseInt(h.substring(0, 2), 16),
+ parseInt(h.substring(2, 4), 16),
+ parseInt(h.substring(4, 6), 16),
+ ];
+ }
+ function hexToRgbStr(hex) {
+ var rgb = hexToRgb(hex);
+ return `${rgb[0]},${rgb[1]},${rgb[2]}`;
+ }
+ function hex(c) {
+ var s = "0123456789abcdef";
+ var i = parseInt(c, 10);
+ if (i === 0 || isNaN(c)) {
+ return "00";
+ }
+ i = Math.round(Math.min(Math.max(0, i), 255));
+ return s.charAt((i - (i % 16)) / 16) + s.charAt(i % 16);
+ }
+ function convertRgbToHex(rgb) {
+ var aColor = rgb
+ .replace(/(?:(|)|rgb|RGB)*/g, "")
+ .replace("(", "")
+ .replace(")", "")
+ .split(",");
+ return "#" + hex(aColor[0]) + hex(aColor[1]) + hex(aColor[2]);
+ }
+ function generateGradientColor(colorStart, colorEnd, colorCount) {
+ var start = hexToRgb(colorStart);
+ var end = hexToRgb(colorEnd);
+ var alpha = 0.0;
+ var rt = [];
+ for (var i = 0; i < colorCount; i++) {
+ var c = [];
+ alpha += 1.0 / colorCount;
+ c[0] = start[0] * alpha + (1 - alpha) * end[0];
+ c[1] = start[1] * alpha + (1 - alpha) * end[1];
+ c[2] = start[2] * alpha + (1 - alpha) * end[2];
+ rt.push(`${c[0]},${c[1]},${c[2]}`);
+ }
+ return rt;
+ }
+ function genRgbGradientColors(numSquares, firstRgb, secondRgb) {
+ var rgb = [];
+ var first = firstRgb.split(",");
+ var second = secondRgb.split(",");
+ var diff1 = first[0] - second[0];
+ var diff2 = first[1] - second[1];
+ var diff3 = first[2] - second[2];
+ var mult1 = diff1 / (numSquares - 1);
+ var mult2 = diff2 / (numSquares - 1);
+ var mult3 = diff3 / (numSquares - 1);
+ var colour = new Array(3);
+ for (var i = 0; i < numSquares; i++) {
+ colour[0] = Math.floor(first[0] - mult1 * i);
+ colour[1] = Math.floor(first[1] - mult2 * i);
+ colour[2] = Math.floor(first[2] - mult3 * i);
+ rgb.push(`${colour[0]},${colour[1]},${colour[2]}`);
+ }
+ return rgb;
+ }
+ return {
+ generateGradientColor: generateGradientColor,
+ genRgbGradientColors: genRgbGradientColors,
+ colorHex: hexToRgbStr,
+ convertRgbToHex: convertRgbToHex,
+ };
+ }
+ DGraph.ColorUtils = ColorUtils;
+ })(DGraph);
+ var VisualGraph = function (container, config) {
+ if (container == null) {
+ return;
+ }
+ this.defaultConfig = {
+ node: {
+ showlabel:true,
+ label: {
+ show: false,
+ color: "50,50,50",
+ font: "normal 1px Arial",
+ wrapText: true,
+ textPosition: "Bottom_Center",
+ textOffsetX: 0,
+ textOffsetY: 0,
+ background: null,
+ borderWidth: 0,
+ borderColor: null,
+ },
+ shape: "circle",
+ color: "30,160,255",
+ borderColor: "20,20,20",
+ borderAlpha: 1,
+ borderWidth: 0,
+ borderRadius: 0,
+ lineDash: [0],
+ alpha: 1,
+ size: 0,
+ width: 60,
+ height: 60,
+ image: null,
+ selected: {
+ borderColor: "140,248,241",
+ borderAlpha: 1,
+ borderWidth: 10,
+ showShadow: true,
+ shadowColor: "140,248,241",
+ shadowBlur: 100,
+ },
+ onClick: function (event, node) {},
+ ondblClick: function (event, node) {},
+ onMouseUp: function (event, node) {},
+ onMouseDown: function (event, node) {},
+ onMouseOver: function (event, node) {},
+ onMouseOut: function (event, node) {},
+ onMousedrag: function (event, node) {},
+ },
+ link: {
+ label: { show: true, color: "20,20,20", font: "normal 13px Arial" },
+ lineType: "direct",
+ colorType: "defined",
+ color: "10,10,10",
+ alpha: 1,
+ lineWidth: 2,
+ lineDash: [0],
+ showArrow: true,
+ arrowType: "arrow",
+ selected: {
+ color: "255,0,0",
+ alpha: 1,
+ lineWidth: 8,
+ showShadow: false,
+ shadowColor: "10,250,10",
+ },
+ onClick: function (event, link) {},
+ ondblClick: function (event, link) {},
+ onMouseUp: function (event, link) {},
+ onMouseDown: function (event, link) {},
+ onMouseOver: function (event, link) {},
+ onMouseOut: function (event, link) {},
+ },
+ highLightNeiber: false,
+ wheelZoom: 1,
+ noElementClick: function (event, graphvis) {},
+ noElementkeyUp: function (event) {},
+ noElementkeyDown: function (event) {},
+ mouseWheel: function (event) {},
+ mouseDrag: function (event) {},
+ onBoxSelectEndEvent: function (selectedNodes) {},
+ };
+ var self = this;
+ this.autoLayout = false;
+ this.forceOptions = {
+ size: [1200, 800],
+ friction: 0.75,
+ linkDistance: 120,
+ linkStrength: 0.05,
+ charge: -200,
+ gravity: 0.0001,
+ noverlap: false,
+ alpha: 0.8,
+ theta: 0.5,
+ loopName: null,
+ };
+ if (!config) {
+ this.config = this.defaultConfig;
+ } else {
+ this.resetConfig(config);
+ }
+ var miniMapConfig = this.deepExtend(
+ { container: "default", width: 200, height: 160, viewColor: "#3ca9f1" },
+ this.config.miniMap || {},
+ true,
+ true,
+ );
+ this.stage = new DGraph.Stage(container, miniMapConfig);
+ this.canvas = this.stage.canvas;
+ this.scene = null;
+ this.nodes = [];
+ this.links = [];
+ this.nodeIdIndex = 1;
+ this.currentNode = null;
+ this.currentLink = null;
+ this.showLinkFlag = true;
+ this.isDerictedGraph = true;
+ this.clusterGroups = [];
+ this.currentCluster = null;
+ this.currentLayout = null;
+ this.drawLinkFlag = false;
+ this.virNode = null;
+ this.drawLineCallback = function (link) {
+ return link;
+ };
+ this.sceneEvent = null;
+ this.init();
+ };
+ VisualGraph.prototype.init = function () {
+ var self = this;
+ this.stage.wheelZoom = this.config.wheelZoom;
+ if (self.scene != null) {
+ self.scene.clear();
+ self.stage.remove(self.scene);
+ }
+ self.scene = new DGraph.Scene(this.stage);
+ self.nodes = [];
+ self.links = [];
+ self.initDrawLinkBase();
+ };
+ VisualGraph.prototype.resetConfig = function (config) {
+ var self = this;
+ config.node.showlabel = true;
+ this.config = this.deepExtend(this.defaultConfig, config || {}, true, true);
+ if (
+ this.config.layout &&
+ this.config.layout["type"] == "force" &&
+ this.config.layout["options"]
+ ) {
+ this.autoLayout = true;
+ setTimeout(function () {
+ (self.forceOptions.friction =
+ Number(self.config.layout.options["friction"]) || 0.9),
+ (self.forceOptions.linkDistance =
+ Number(self.config.layout.options["linkDistance"]) || 150),
+ (self.forceOptions.linkStrength =
+ Number(self.config.layout.options["linkStrength"]) || 0.05),
+ (self.forceOptions.charge =
+ Number(self.config.layout.options["charge"]) || -150),
+ (self.forceOptions.gravity =
+ Number(self.config.layout.options["gravity"]) || 0.01),
+ (self.forceOptions.noverlap =
+ self.config.layout.options["noverlap"] || false);
+ self.forceOptions.size = [
+ self.stage.width || 1200,
+ self.stage.height || 600,
+ ];
+ self.autoLayout = true;
+ }, 1000);
+ }
+ this.config.showlabel = true;
+ this.defaultNodeColor = this.config.node.color;
+ this.highLightNeiber = this.config.highLightNeiber;
+ };
+ VisualGraph.prototype.initDrawLinkBase = function () {
+ var _self = this;
+ var virNode = new DGraph.Node();
+ virNode.shape = "circle";
+ virNode.radius = 1;
+ virNode.width = 2;
+ virNode.height = 2;
+ virNode.show = virNode;
+ virNode.alpha = 0;
+ _self.virNode = virNode;
+ _self.scene.mousemove(function (e) {
+ if (_self.drawLinkFlag) {
+ if (!_self.virNode.show) {
+ _self.virNode.show = true;
+ _self.scene.add(_self.virNode);
+ }
+ if (_self.virLink == null) {
+ var linkConfig = _self.config["link"];
+ var virLink = new DGraph.Edge(_self.currentNode, _self.virNode);
+ virLink.lineWidth = linkConfig["lineWidth"];
+ virLink.showArrow = linkConfig["showArrow"];
+ virLink.strokeColor = linkConfig["color"];
+ virLink.selectedColor = linkConfig["color"];
+ virLink.lineDash = [3, 5, 5];
+ _self.virLink = virLink;
+ _self.scene.add(_self.virLink);
+ }
+ _self.virNode.cx = e.x - 2;
+ _self.virNode.cy = e.y + 2;
+ }
+ });
+ _self.scene.dbclick(function (e) {
+ _self.drawLinkFlag = false;
+ if (_self.virNode.show) {
+ _self.virNode.show = false;
+ _self.scene.remove(_self.virNode);
+ }
+ if (_self.virLink) {
+ _self.scene.remove(_self.virLink);
+ _self.virLink = null;
+ }
+ });
+ _self.scene.click(function (e) {
+ _self.hideAllRightMenu();
+ if (e.target == null) {
+ if (_self.highLightNeiber) {
+ _self.restoreHightLight();
+ }
+ }
+ });
+ _self.scene.mouseup(function (e) {
+ _self.setMouseModel("normal");
+ var mouseUp = _self.config.mouseUp;
+ if (mouseUp && typeof mouseUp === "function") {
+ mouseUp(e, _self);
+ }
+ });
+ _self.scene.keyup(function (e) {
+ let noElementkeyUp = _self.config.noElementkeyUp;
+ if (noElementkeyUp && typeof noElementkeyUp === "function") {
+ noElementkeyUp(e, _self);
+ }
+ });
+ _self.scene.keydown(function (e) {
+ let noElementkeyDown = _self.config.noElementkeyDown;
+ if (noElementkeyDown && typeof noElementkeyDown === "function") {
+ if (e.key === "Control") {
+ _self.setMouseModel("select");
+ }
+ noElementkeyDown(e, _self);
+ }
+ });
+ _self.scene.mousedrag(function (e) {
+ var mouseDrag = _self.config.mouseDrag;
+ if (mouseDrag && typeof mouseDrag === "function") {
+ mouseDrag(e, _self);
+ }
+ });
+ _self.scene.mouseup(function (e) {
+ if (e.target == null) {
+ _self.hideAllRightMenu();
+ _self.currentNode = null;
+ _self.currentLink = null;
+ if (_self.highLightNeiber) {
+ _self.restoreHightLight();
+ }
+ var noElementClick = _self.config["noElementClick"];
+ if (noElementClick && typeof noElementClick === "function") {
+ noElementClick(e, _self);
+ }
+ } else {
+ if (e.target.elementType == "node") {
+ _self.currentLink = null;
+ } else {
+ _self.currentNode = null;
+ }
+ }
+ if (this.areaSelect) {
+ var onBoxSelectEndEvent = _self.config["onBoxSelectEndEvent"];
+ if (onBoxSelectEndEvent && typeof onBoxSelectEndEvent === "function") {
+ var $ = this;
+ setTimeout(function () {
+ onBoxSelectEndEvent($.boxSelectedNodes);
+ $.boxSelectedNodes = null;
+ }, 500);
+ } else {
+ this.boxSelectedNodes = null;
+ }
+ }
+ });
+ };
+ VisualGraph.prototype.deepExtend = function (
+ a,
+ b,
+ protoExtend,
+ allowDeletion,
+ ) {
+ for (var prop in b) {
+ if (b.hasOwnProperty(prop) || protoExtend === true) {
+ if (b[prop] && b[prop].constructor === Object) {
+ if (a[prop] === undefined) {
+ a[prop] = {};
+ }
+ if (a[prop].constructor === Object) {
+ this.deepExtend(a[prop], b[prop], protoExtend);
+ } else {
+ if (
+ b[prop] === null &&
+ a[prop] !== undefined &&
+ allowDeletion === true
+ ) {
+ delete a[prop];
+ } else {
+ a[prop] = b[prop];
+ }
+ }
+ } else if (Array.isArray(b[prop])) {
+ a[prop] = [];
+ for (let i = 0; i < b[prop].length; i++) {
+ a[prop].push(b[prop][i]);
+ }
+ } else {
+ if (
+ b[prop] === null &&
+ a[prop] !== undefined &&
+ allowDeletion === true
+ ) {
+ delete a[prop];
+ } else {
+ a[prop] = b[prop];
+ }
+ }
+ }
+ }
+ return a;
+ };
+ VisualGraph.prototype.hideAllRightMenu = function () {
+ var _self = this;
+ if (_self.config.hasOwnProperty("rightMenu")) {
+ if (_self.config.rightMenu.hasOwnProperty("nodeMenu")) {
+ var nodeHide = _self.config["rightMenu"]["nodeMenu"]["hide"];
+ if (typeof nodeHide === "function") {
+ _self.config["rightMenu"]["nodeMenu"].hide();
+ }
+ }
+ if (_self.config.rightMenu.hasOwnProperty("linkMenu")) {
+ var linkHide = _self.config["rightMenu"]["linkMenu"]["hide"];
+ if (typeof linkHide === "function") {
+ _self.config["rightMenu"]["linkMenu"].hide();
+ }
+ }
+ if (_self.config.rightMenu.hasOwnProperty("clusterMenu")) {
+ var clusterHide = _self.config["rightMenu"]["clusterMenu"]["hide"];
+ if (typeof clusterHide === "function") {
+ _self.config["rightMenu"]["clusterMenu"].hide();
+ }
+ }
+ }
+ };
+ VisualGraph.prototype.drawData = function (data) {
+ var self = this;
+ if (data == null) {
+ return;
+ }
+ this.init();
+ var nodeIdMapNode = {};
+ var node = null;
+ (data.nodes || []).forEach(function (n, i) {
+ n.scale = 1;
+ node = self.newNode(n, i);
+ node.showlabel = true;
+ self.scene.add(node);
+ self.nodes.push(node);
+ nodeIdMapNode[n.id] = node;
+ });
+ var source, target, link;
+ (data.links || []).forEach(function (l) {
+ source = nodeIdMapNode[l.source];
+ target = nodeIdMapNode[l.target];
+ if (source && target) {
+ link = self.newEdge(source, target);
+ link.showlabel = l.showlabel || self.config.link.label.show;
+ link.fontColor = l.fontColor || self.config.link.label.color;
+ link.font = l.font || self.config.link.label.font;
+ link.colorType = l.colorType || self.config.link.colorType;
+ link.strokeColor = self.getColor(l, self.config.link.color);
+ link.lineType = l.lineType || self.config.link.lineType;
+ link.type = l.type || "";
+ link.id = l.id || "";
+ link.label = l.label || l.type || "";
+ link.weight = l.weight || 2;
+ link.value = l.value || 2;
+ link.lineWidth = l.lineWidth || self.config.link.lineWidth;
+ link.properties = l.properties || {};
+ self.scene.add(link);
+ self.links.push(link);
+ }
+ });
+ self.refresh();
+ if (self.autoLayout) {
+ self.runLayoutEngin(self.nodes, self.links, 0.9);
+ }
+ };
+ VisualGraph.prototype.customStyle = function (callback) {
+ if (callback && typeof callback === "function") {
+ return callback(this.stage.graphics);
+ }
+ return null;
+ };
+ VisualGraph.prototype.translateToCenter = function () {
+ this.scene.translateToCenter();
+ this.refresh();
+ };
+ VisualGraph.prototype.getColor = function (ele, defaultColor) {
+ var color = ele.color;
+ if (color) {
+ color = color.replace("rgb(", "").replace(")", "");
+ } else {
+ color = defaultColor || this.defaultNodeColor;
+ }
+ return color;
+ };
+ VisualGraph.prototype.addNodesInGroup = function (conf, childNodes) {
+ conf = conf || {};
+ var group = new DGraph.Group(conf.label, conf.fixed || false);
+ group.x = conf.x || 500;
+ group.y = conf.y || 300;
+ group.fillColor = conf.color || "150,250,200";
+ group.alpha = conf.alpha || 0.8;
+ group.width = conf.width || 100;
+ group.height = conf.height || 100;
+ this.scene.add(group);
+ if (Array.isArray(childNodes)) {
+ childNodes.forEach((node) => {
+ group.add(node);
+ });
+ } else {
+ group.add(childNodes);
+ }
+ this.refresh();
+ return group;
+ };
+ VisualGraph.prototype.createGroup = function (conf) {
+ conf = conf || {};
+ var group = new DGraph.Group(conf.label, conf.fixed || false);
+ group.x = conf.x || 10;
+ group.y = conf.y || 10;
+ group.fillColor = conf.color || "150,250,200";
+ group.alpha = conf.alpha || 0.8;
+ group.width = conf.width || 100;
+ group.height = conf.height || 100;
+ this.scene.add(group);
+ this.refresh();
+ return group;
+ };
+ VisualGraph.prototype.newNode = function (n) {
+ var self = this;
+ var node = new DGraph.Node();
+ node.x = n.x == null ? Math.round(Math.random() * this.stage.width) : n.x;
+ node.y = n.y == null ? Math.round(Math.random() * this.stage.height) : n.y;
+ node.id = n.id;
+ node.type = n.type || "default";
+ node.cluster = n.cluster || "default";
+ node.scaleX = node.scaleY = n.scale || Number(1);
+ node.label = n.label || n.id;
+ node.alpha = n.alpha || self.config.node.alpha;
+ node.fontColor = n.fontColor || self.config.node.label.color;
+ node.textPosition = n.textPosition || self.config.node.label.textPosition;
+ node.font = n.font || self.config.node.label.font;
+ node.borderWidth = n.borderWidth || self.config.node.borderWidth;
+ node.borderRadius = n.borderRadius || self.config.node.borderRadius;
+ node.borderColor = n.borderColor || self.config.node.borderColor;
+ node.borderAlpha = n.borderAlpha || self.config.node.borderAlpha;
+ node.showlabel = n.showlabel || self.config.node.label.show;
+ node.wrapText = self.config.node.label.wrapText;
+ node.showShadow = n.showShadow || self.config.node.selected.showShadow;
+ node.shadowColor = n.shadowColor || self.config.node.selected.shadowColor;
+ node.shadowBlur = n.shadowBlur || self.config.node.selected.shadowBlur;
+ node.selectedBorderColor =
+ n.selectedBorderColor || self.config.node.selected.borderColor;
+ node.selectedBorderAlpha =
+ n.selectedBorderAlpha || self.config.node.selected.borderAlpha;
+ node.selectedBorderWidth =
+ n.selectedBorderWidth || self.config.node.selected.borderWidth;
+ node.lineDash = n.lineDash || self.config.node.lineDash;
+ node.labelBackGround =
+ n.labelBackGround || self.config.node.label.background;
+ node.labelBorderWidth =
+ n.labelBorderWidth || self.config.node.label.borderWidth;
+ node.labelBorderColor =
+ n.labelBorderColor || self.config.node.label.borderColor;
+ node.textOffsetX = n.textOffsetX || self.config.node.label.textOffsetX;
+ node.textOffsetY = n.textOffsetY || self.config.node.label.textOffsetY;
+ node.icon = n.icon;
+ node.tipText = n.tipText;
+ node.weight = 1;
+ node.px = node.x;
+ node.py = node.y;
+ node.charge = self.forceOptions.charge;
+ node.properties = n.properties || {};
+ if (self.config.clusters && self.config.clusters[node.cluster]) {
+ node.fillColor =
+ self.config.clusters[node.cluster]["color"] || self.config.node.color;
+ node.shape =
+ self.config.clusters[node.cluster]["shape"] || self.config.node.shape;
+ node.size =
+ self.config.clusters[node.cluster]["size"] || self.config.node.size;
+ } else {
+ node.fillColor = self.getColor(n, this.defaultNodeColor);
+ node.shape = n.shape || self.config.node.shape;
+ node.size = n.size || self.config.node.size;
+ }
+ if (!node.size || node.size == 0) {
+ node.width = n.width || self.config.node.width;
+ node.height = n.height || self.config.node.height;
+ } else {
+ node.width = node.height = node.size;
+ }
+ if (n.image && n.image.length > 0) {
+ node.setImage(n.image);
+ } else {
+ node.setImage(self.config.node.image || "");
+ }
+ node.click(function (event) {
+ self.currentNode = this;
+ if (self.drawLinkFlag && self.virLink != null) {
+ var link = self.newEdge(self.virLink.source, this);
+ link.strokeColor = self.config.link.color;
+ self.links.push(link);
+ self.scene.add(link);
+ if (self.virNode.show) {
+ self.virNode.show = false;
+ self.scene.remove(self.virNode);
+ }
+ self.drawLinkFlag = false;
+ if (self.virLink) {
+ self.scene.remove(self.virLink);
+ self.virLink = null;
+ }
+ if (
+ self.drawLineCallback &&
+ typeof self.drawLineCallback === "function"
+ ) {
+ self.drawLineCallback(link);
+ }
+ }
+ if (self.highLightNeiber) {
+ self.restoreHightLight();
+ self.highLightNeiberNodes(this, 0.1);
+ }
+ if (self.config.node.hasOwnProperty("onClick")) {
+ var onClick = self.config.node["onClick"];
+ if (typeof onClick === "function") {
+ onClick(event, this);
+ }
+ }
+ });
+ node.dbclick(function (evt) {
+ this.fixed = !this.fixed;
+ if (self.config.node.hasOwnProperty("ondblClick")) {
+ var ondblClick = self.config.node["ondblClick"];
+ if (typeof ondblClick === "function") {
+ ondblClick(event, this);
+ }
+ }
+ });
+ node.mousedrag(function (evt) {
+ this.fixed = true;
+ this.px = this.x;
+ this.py = this.y;
+ if (this.isDragging || self.scene.selectedElements.length > 1) {
+ return false;
+ }
+ this.isDragging = true;
+ if (self.autoLayout) {
+ self.runLayoutEngin(self.nodes, self.links, 0.5);
+ }
+ if (self.config.node.hasOwnProperty("onMousedrag")) {
+ var onMousedrag = self.config.node["onMousedrag"];
+ if (typeof onMousedrag === "function") {
+ onMousedrag(event, this);
+ }
+ }
+ });
+ node.mouseup(function (evt) {
+ self.currentNode = this;
+ this.fixed = true;
+ this.px = this.x;
+ this.py = this.y;
+ this.isDragging = false;
+ if (evt.button == 2) {
+ self.showNodeRightMenu(evt, this);
+ }
+ if (self.config.node.hasOwnProperty("onMouseUp")) {
+ var onMouseUp = self.config.node["onMouseUp"];
+ if (typeof onMouseUp === "function") {
+ onMouseUp(event, this);
+ }
+ }
+ });
+ node.mousedown(function (evt) {
+ self.currentNode = this;
+ this.fixed = true;
+ this.px = this.x;
+ this.py = this.y;
+ if (self.config.node.hasOwnProperty("onMouseDown")) {
+ var onMouseDown = self.config.node["onMouseDown"];
+ if (typeof onMouseDown === "function") {
+ onMouseDown(event, this);
+ }
+ }
+ });
+ node.mouseover(function (evt) {
+ if (self.config.node.hasOwnProperty("onMouseOver")) {
+ var onMouseOver = self.config.node["onMouseOver"];
+ if (typeof onMouseOver === "function") {
+ onMouseOver(event, this);
+ }
+ }
+ });
+ node.mouseout(function (evt) {
+ if (self.config.node.hasOwnProperty("onMouseOut")) {
+ var onMouseOut = self.config.node["onMouseOut"];
+ if (typeof onMouseOut === "function") {
+ onMouseOut(event, this);
+ }
+ }
+ });
+ return node;
+ };
+ VisualGraph.prototype.refresh = function () {
+ this.stage &&
+ ((this.stage.needRepaint = true),
+ this.stage.repaint(),
+ (this.stage.needRepaint = false));
+ };
+ VisualGraph.prototype.highLightNeiberNodes = function (_node, alpha) {
+ var self = this;
+ self.nodes.map(function (n) {
+ n.t_alpha = n.alpha;
+ n.alpha = alpha || 0.1;
+ });
+ _node.alpha = _node.t_alpha;
+ (_node.inLinks || []).map(function (link) {
+ if (link.source.visible) {
+ link.source.alpha = link.source.t_alpha;
+ }
+ });
+ (_node.outLinks || []).map(function (link) {
+ if (link.target.visible) {
+ link.target.alpha = link.target.t_alpha;
+ }
+ });
+ if (self.showLinkFlag) {
+ self.links.map(function (link) {
+ link.visible = false;
+ });
+ (_node.inLinks || []).map(function (link) {
+ if (link.source.visible) {
+ link.visible = true;
+ }
+ });
+ (_node.outLinks || []).map(function (link) {
+ if (link.target.visible) {
+ link.visible = true;
+ }
+ });
+ }
+ };
+ VisualGraph.prototype.restoreHightLight = function () {
+ var self = this;
+ self.nodes.map(function (n) {
+ n.alpha = n.t_alpha || n.alpha;
+ });
+ if (self.showLinkFlag) {
+ self.links.map(function (link) {
+ if (link.source.visible && link.target.visible) {
+ link.visible = true;
+ }
+ });
+ }
+ };
+ VisualGraph.prototype.lockNode = function (node) {
+ if (node && node != null) {
+ node.fixed = true;
+ node.dragable = false;
+ }
+ };
+ VisualGraph.prototype.unLockNode = function (node) {
+ if (node && node != null) {
+ node.fixed = false;
+ node.dragable = true;
+ }
+ };
+ VisualGraph.prototype.showNodeRightMenu = function (event, _node) {
+ var self = this;
+ if (self.config.hasOwnProperty("rightMenu")) {
+ if (self.config["rightMenu"].hasOwnProperty("nodeMenu")) {
+ var nodeShow = self.config["rightMenu"]["nodeMenu"]["show"];
+ if (typeof nodeShow === "function") {
+ self.config["rightMenu"]["nodeMenu"].show(event, self, _node);
+ }
+ }
+ }
+ };
+ VisualGraph.prototype.showLinkRightMenu = function (event, link) {
+ var self = this;
+ if (self.config.hasOwnProperty("rightMenu")) {
+ if (self.config["rightMenu"].hasOwnProperty("linkMenu")) {
+ var linkShow = self.config["rightMenu"]["linkMenu"]["show"];
+ if (typeof linkShow === "function") {
+ self.config["rightMenu"]["linkMenu"].show(event, self, link);
+ }
+ }
+ }
+ };
+ VisualGraph.prototype.showClusterRightMenu = function (event, group) {
+ var self = this;
+ if (self.config.hasOwnProperty("rightMenu")) {
+ if (self.config["rightMenu"].hasOwnProperty("groupMenu")) {
+ var show = self.config["rightMenu"]["groupMenu"]["show"];
+ if (typeof show === "function") {
+ self.config["rightMenu"]["groupMenu"].show(event, self, group);
+ }
+ }
+ }
+ };
+ VisualGraph.prototype.colorHex = function (hexColor) {
+ var ctool = new DGraph.ColorUtils();
+ return ctool.colorHex(hexColor) || "0,0,250";
+ };
+ VisualGraph.prototype.newEdge = function (source, target, visible = true) {
+ if (source == null || target == null) {
+ return false;
+ }
+ var self = this;
+ var link = new DGraph.Edge(source, target, null);
+ link.lineWidth = self.config.link.lineWidth;
+ link.alpha = self.config.link.alpha;
+ link.strokeColor = self.config.link.color;
+ link.showArrow = self.config.link.showArrow;
+ link.arrowType = self.config.link.arrowType;
+ link.lineType = self.config.link.lineType;
+ link.lineDash = self.config.link.lineDash;
+ link.fontColor = self.config.link.label.color;
+ link.showShadow = self.config.link.selected.showShadow;
+ link.shadowColor = self.config.link.selected.shadowColor;
+ link.selectedColor = self.config.link.selected.color;
+ link.selectedAlpha = self.config.link.selected.alpha;
+ link.colorType = self.config.link.colorType;
+ link.labelBackGround = self.config.link.label.background;
+ link.labelBorderWidth = self.config.link.label.borderWidth;
+ link.labelBorderColor = self.config.link.label.borderColor;
+ link.distance = self.forceOptions.linkDistance;
+ link.strength = self.forceOptions.linkStrength;
+ link.weight = 1;
+ link.visible = visible;
+ ++source.weight;
+ ++target.weight;
+ link.mouseup(function (evt) {
+ self.currentLink = this;
+ if (evt.button == 2) {
+ self.showLinkRightMenu(evt, this);
+ }
+ });
+ link.click(function (event) {
+ if (self.config.link.hasOwnProperty("onClick")) {
+ var onClick = self.config.link["onClick"];
+ if (typeof onClick === "function") {
+ onClick(event, this);
+ }
+ }
+ });
+ link.dbclick(function (event) {
+ if (self.config.link.hasOwnProperty("ondblClick")) {
+ var ondbClick = self.config.link["ondblClick"];
+ if (typeof ondbClick === "function") {
+ ondbClick(event, this);
+ }
+ }
+ });
+ link.mousedown(function (event) {
+ if (self.config.link.hasOwnProperty("onMouseDown")) {
+ var onMouseDown = self.config.link.onMouseDown;
+ if (typeof onMouseDown === "function") {
+ onMouseDown(event, this);
+ }
+ }
+ });
+ link.mouseup(function (event) {
+ if (self.config.link.hasOwnProperty("onMouseUp")) {
+ var onMouseUp = self.config.link.onMouseUp;
+ if (typeof onMouseUp === "function") {
+ onMouseUp(event, this);
+ }
+ }
+ });
+ link.mouseover(function (event) {
+ if (self.config.link.hasOwnProperty("onMouseOver")) {
+ var onMouseOver = self.config.link["onMouseOver"];
+ if (typeof onMouseOver === "function") {
+ onMouseOver(event, this);
+ }
+ }
+ });
+ link.mouseout(function (event) {
+ if (self.config.link.hasOwnProperty("onMouseOut")) {
+ var onMouseOut = self.config.link["onMouseOut"];
+ if (typeof onMouseOut === "function") {
+ onMouseOut(event, this);
+ }
+ }
+ });
+ return link;
+ };
+ VisualGraph.prototype.addNodes = function (nodes) {
+ if ((!nodes) instanceof Array || nodes.length == 0) {
+ return;
+ }
+ var self = this;
+ var nodeIdMapNode = new Map();
+ self.nodes.forEach((node) => {
+ nodeIdMapNode.set(node.id, node);
+ });
+ var newNodes = [],
+ node = null;
+ nodes.forEach((_node) => {
+ if (nodeIdMapNode.get(_node.id) == null) {
+ node = self.newNode(_node);
+ self.scene.add(node);
+ self.nodes.push(node);
+ newNodes.push(node);
+ }
+ });
+ self.refresh();
+ return newNodes;
+ };
+ VisualGraph.prototype.addNode = function (_node) {
+ var self = this;
+ var node = self.newNode(_node);
+ self.scene.add(node);
+ self.nodes.push(node);
+ self.refresh();
+ return node;
+ };
+ VisualGraph.prototype.addEdges = function (edges) {
+ if ((!edges) instanceof Array || edges.length == 0) {
+ return;
+ }
+ var self = this;
+ var linkIdMapLink = new Map();
+ self.links.forEach((link) => {
+ if (link.id) {
+ linkIdMapLink.set(link.id, link);
+ }
+ });
+ var idMapNode = new Map();
+ self.nodes.forEach((node) => {
+ idMapNode.set(node.id, node);
+ });
+ var newEdges = [];
+ var sourceNode = null,
+ targetNode = null,
+ link = null;
+ edges.forEach((_link) => {
+ if (linkIdMapLink.get(_link.id) == null) {
+ sourceNode = idMapNode.get(_link.source);
+ targetNode = idMapNode.get(_link.target);
+ if (sourceNode != null && targetNode != null) {
+ link = self.newEdge(sourceNode, targetNode);
+ self._copyEdgePropers(link, _link);
+ self.scene.add(link);
+ self.links.push(link);
+ newEdges.push(link);
+ }
+ }
+ });
+ self.refresh();
+ return newEdges;
+ };
+ VisualGraph.prototype.addEdge = function (_link) {
+ var self = this;
+ var sourceNode = this.nodes.filter(function (n) {
+ return n.id == _link.source;
+ })[0];
+ var targetNode = this.nodes.filter(function (n) {
+ return n.id == _link.target;
+ })[0];
+ var link = null;
+ if (sourceNode && targetNode) {
+ link = self.newEdge(sourceNode, targetNode);
+ self._copyEdgePropers(link, _link);
+ self.scene.add(link);
+ self.links.push(link);
+ self.refresh();
+ }
+ return link;
+ };
+ VisualGraph.prototype._copyEdgePropers = function (link, edge) {
+ if (link != null && edge != null) {
+ var self = this;
+ link.id = edge.id || "";
+ link.type = edge.type || "default";
+ link.label = edge.label || "";
+ link.showlabel = edge.showlabel || self.config.link.label.show;
+ link.lineWidth = Number(edge.lineWidth) || self.config.link.lineWidth;
+ link.strokeColor = self.getColor(edge, self.config.link.color);
+ link.weight = Number(edge.weight) || 1;
+ link.lineType = edge.lineType || self.config.link.lineType;
+ link.lineDash = edge.lineDash || self.config.link.lineDash;
+ link.font = edge.font || self.config.link.label.font;
+ link.fontColor = edge.fontColor || self.config.link.label.color;
+ link.properties = edge.properties || {};
+ }
+ };
+ VisualGraph.prototype.getGraphData = function () {
+ var self = this;
+ return { nodes: self.nodes, links: self.links };
+ };
+ VisualGraph.prototype.getVisibleData = function () {
+ var self = this;
+ var visibleNodes = self.nodes.filter(function (n) {
+ return n.visible == true;
+ });
+ var visibleLinks = self.links.filter(function (l) {
+ var source = l.source,
+ target = l.target;
+ return source.visible == true && target.visible == true;
+ });
+ visibleNodes.forEach((n) => {
+ n.fixed = false;
+ });
+ return { nodes: visibleNodes, links: visibleLinks };
+ };
+ VisualGraph.prototype.setZoom = function (type) {
+ var self = this;
+ if (type == "zoomOut") {
+ self.stage.zoomOut();
+ } else if (type == "zoomIn") {
+ self.stage.zoomIn();
+ } else if (type == "zoom1") {
+ self.stage.centerAndZoom();
+ self.scene.scaleX = 1;
+ self.scene.scaleY = 1;
+ } else {
+ self.stage.centerAndZoom();
+ }
+ self.refresh();
+ };
+ VisualGraph.prototype.setZoomRange = function (range = [0.1, 10]) {
+ if (range instanceof Array && range.length == 2) {
+ var min = Number(range[0]) || 0.1;
+ var max = Number(range[1]) || 10;
+ if (min < max) {
+ this.scene.scaleRange = [min, max];
+ }
+ }
+ };
+ VisualGraph.prototype.moveCenter = function (scale = 1) {
+ this.scene.scaleX = scale;
+ this.scene.scaleY = scale;
+ this.scene.translateToCenter();
+ this.refresh();
+ };
+ VisualGraph.prototype.moveNodeToCenter = function (node, times) {
+ var self = this;
+ if (times != null && Number(times) > 0) {
+ self.scene.translateX = -node.x + self.stage.width / 2;
+ self.scene.translateY = -node.y + self.stage.height / 2;
+ } else {
+ self.scene.setCenter(node.x, node.y);
+ }
+ self.refresh();
+ };
+ VisualGraph.prototype.moveScene = function (direct = "left", distance = 20) {
+ var self = this;
+ switch (direct) {
+ case "left":
+ self.scene.translateX -= Number(distance);
+ break;
+ case "right":
+ self.scene.translateX += Number(distance);
+ break;
+ case "up":
+ self.scene.translateY -= Number(distance);
+ break;
+ case "down":
+ self.scene.translateY += Number(distance);
+ break;
+ default:
+ break;
+ }
+ };
+ VisualGraph.prototype.setLineType = function (type) {
+ this.links.forEach(function (link) {
+ link.lineType = type;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.setNodeShape = function (type) {
+ this.nodes.forEach(function (node) {
+ if (node.shape == "circle") {
+ node.height = node.width;
+ }
+ node.shape = type;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.showNodeLabel = function (flag) {
+ this.nodes.forEach(function (node) {
+ node.showlabel = true;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.showLinkLabel = function (flag) {
+ this.links.forEach(function (link) {
+ link.showlabel = true;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.resize = function () {
+ this.stage.resize();
+ };
+ VisualGraph.prototype.setMouseModel = function (model, type) {
+ if (model == "drag") {
+ this.stage.mode = "drag";
+ } else if (model == "select") {
+ this.stage.mode = "select";
+ if (type && ["rect", "lasso"].indexOf(type) != -1) {
+ this.scene.selectBoxType = type;
+ }
+ } else {
+ this.stage.mode = "normal";
+ }
+ };
+ VisualGraph.prototype.contract = function (curNode) {
+ var _self = this;
+ if (curNode) {
+ var leafNodes = [];
+ (curNode.outLinks || []).forEach(function (l) {
+ if (
+ (l.target.outLinks || []).length == 0 &&
+ (l.target.inLinks || []).length == 1
+ ) {
+ leafNodes.push(l.target);
+ l.visible = false;
+ }
+ });
+ curNode.tipText = leafNodes.length;
+ leafNodes.forEach(function (n) {
+ n.visible = false;
+ });
+ _self.refresh();
+ }
+ };
+ VisualGraph.prototype.expanded = function (curNode) {
+ var _self = this;
+ if (curNode) {
+ var targetNodes = [];
+ (curNode.outLinks || []).forEach(function (l) {
+ var target = l.target;
+ if ((target.outLinks || []).length == 0 && target.visible == false) {
+ l.visible = true;
+ target.visible = true;
+ targetNodes.push(target);
+ }
+ });
+ if (targetNodes.length == 0) {
+ return;
+ }
+ curNode.tipText = null;
+ }
+ };
+ VisualGraph.prototype.saveImage = function (
+ config = {
+ width: 6000,
+ height: 6000,
+ type: "png",
+ fileName: "picture",
+ background: "#fff",
+ textWatermark: {
+ content: "",
+ angle: -30,
+ alpha: 0.2,
+ fontStyle: "bold",
+ fontSize: 60,
+ fontFamliy: "Arial",
+ fontColor: "#666",
+ },
+ },
+ ) {
+ this.stage.saveAsLocalImage(config);
+ };
+ VisualGraph.prototype.exportJsonFile = function (fileName) {
+ var jsonStr = JSON.stringify(this.serialized());
+ funDownload(jsonStr, fileName || "graphvis" + ".json");
+ function funDownload(content, filename) {
+ var blob = new Blob([content], { type: "text/json" });
+ let a = document.createElement("a");
+ let event = new MouseEvent("click");
+ a.download = filename;
+ a.href = window.URL.createObjectURL(blob);
+ a.dataset.downloadurl = ["text/json", a.download, a.href].join(":");
+ a.dispatchEvent(event);
+ }
+ };
+ VisualGraph.prototype.showOverView = function (flag) {
+ if (flag) {
+ this.stage.thumbnail.show();
+ } else {
+ this.stage.thumbnail.destory();
+ }
+ };
+ VisualGraph.prototype.findNode = function (nodeLabel) {
+ var nodes = this.nodes.filter(function (n) {
+ if (n.label == null) return false;
+ return n.label + "" == nodeLabel || n.id == nodeLabel;
+ });
+ if (nodes.length > 0) {
+ var node = nodes[0];
+ node.selected = true;
+ node.showlabel = true;
+ this.currentNode = node;
+ this.focusTargetEle(node);
+ return node;
+ }
+ return null;
+ };
+ VisualGraph.prototype.focusTargetEle = function (ele, params, callback) {
+ ele.selected = true;
+ if (!params) {
+ params = {};
+ }
+ if (!params.x && params.x != 0) {
+ params.x = this.stage.width / 2;
+ }
+ if (!params.y && params.y != 0) {
+ params.y = this.stage.height / 2;
+ }
+ this.scene.translateX = -ele.x + params.x;
+ this.scene.translateY = -ele.y + params.y;
+ this.refresh();
+ callback && callback();
+ };
+ VisualGraph.prototype.converHexToRGB = function (hex) {
+ var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
+ hex = hex.replace(shorthandRegex, function (m, r, g, b) {
+ return r + r + g + g + b + b;
+ });
+ var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
+ if (result) {
+ return (
+ parseInt(result[1], 16) +
+ "," +
+ parseInt(result[2], 16) +
+ "," +
+ parseInt(result[3], 16)
+ );
+ }
+ return "150,150,200";
+ };
+ VisualGraph.prototype.setLabelColor = function (hexColor) {
+ var rgbColor = this.converHexToRGB(hexColor);
+ this.config.node.label.color = rgbColor;
+ this.nodes.forEach(function (node) {
+ node.fontColor = rgbColor;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.hideAllLink = function () {
+ this.showLinkFlag = false;
+ this.links.forEach(function (link) {
+ link.visible = false;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.showAllLink = function () {
+ this.showLinkFlag = true;
+ this.links.forEach(function (link) {
+ if (link.source.visible && link.target.visible) {
+ link.visible = true;
+ }
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.showAllNode = function () {
+ this.nodes.forEach(function (node) {
+ node.alpha = 1;
+ node.visible = true;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.setNodeFont = function (fontSize) {
+ var self = this;
+ self.nodes.forEach(function (n) {
+ n.font = "normal " + fontSize + "px Arial";
+ });
+ self.refresh();
+ };
+ VisualGraph.prototype.setTextPosition = function (textAlign) {
+ var self = this;
+ self.nodes.forEach(function (n) {
+ n.textPosition = textAlign;
+ });
+ self.refresh();
+ };
+ VisualGraph.prototype.setLinkAlpha = function (alpha) {
+ this.links.forEach(function (links) {
+ links.alpha = alpha;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.setLinkArrowShow = function (flag) {
+ this.links.forEach(function (l) {
+ l.showArrow = flag;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.setLinkColor = function (hexColor) {
+ var rgbColor = this.converHexToRGB(hexColor);
+ this.links.forEach(function (link) {
+ link.colorType = "defined";
+ link.strokeColor = rgbColor;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.setLinkColorType = function (type) {
+ var linkColorType = type || "source";
+ this.links.forEach(function (l) {
+ l.colorType = linkColorType;
+ if (linkColorType == "defined") {
+ l.strokeColor = self.config.link.color || "50,50,50";
+ }
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.setLinkFont = function (fontSize) {
+ var self = this;
+ self.links.forEach(function (l) {
+ l.font = "normal " + fontSize + "px Arial";
+ l.textOffsetX = -Number(fontSize);
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.setLinkLabelColor = function (hexColor) {
+ var self = this;
+ var rgbColor = this.converHexToRGB(hexColor);
+ self.links.forEach(function (l) {
+ l.fontColor = rgbColor;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.resetNodeInfo = function (nodeInfo) {
+ var node = this.currentNode;
+ if (node) {
+ node.label = this.currentNode.text = nodeInfo.name;
+ node.width = Number(nodeInfo.width) || Number(nodeInfo.size) || 60;
+ node.height = Number(nodeInfo.height) || Number(nodeInfo.size) || 60;
+ node.scaleX = node.scaleY = Number(nodeInfo.scale) || 1;
+ node.fillColor = this.converHexToRGB(nodeInfo.fillColor);
+ node.shape = nodeInfo.shape;
+ node.showlabel = true;
+ node.imageUrl = nodeInfo.image;
+ node.setImage(nodeInfo.image);
+ this.refresh();
+ }
+ };
+ VisualGraph.prototype.resetEdgeStyle = function (lineInfo) {
+ var self = this;
+ var line = self.currentLink;
+ if (line) {
+ line.label = lineInfo["label"];
+ line.text = line.label;
+ line.type = line.label;
+ line.lineWidth = lineInfo["lineWidth"];
+ line.lineType = lineInfo["lineType"];
+ if (lineInfo["lineDash"]) {
+ line.lineDash = lineInfo["lineDash"].split(",");
+ }
+ var color = lineInfo["edgeColor"];
+ if (color && color.length > 0) {
+ line.strokeColor = self.converHexToRGB(color);
+ line.fontColor = line.strokeColor;
+ line.colorType = "defined";
+ }
+ line.showlabel = true;
+ this.refresh();
+ }
+ };
+ VisualGraph.prototype.addClusterContainer = function (
+ clusters,
+ avoidOverlap,
+ ) {
+ var self = this;
+ if (clusters == null) {
+ return;
+ }
+ if (avoidOverlap == undefined || avoidOverlap == null) {
+ avoidOverlap = false;
+ }
+ self.clusterGroups.forEach(function (group) {
+ self.scene.remove(group);
+ });
+ self.clusterGroups = [];
+ for (var clusterKey in clusters) {
+ var cluster = clusters[clusterKey];
+ var clusterNodes = self.nodes.filter(function (node) {
+ return node.cluster == clusterKey;
+ });
+ var size = cluster.size,
+ rate = cluster.rate,
+ color = cluster.color;
+ if (clusterNodes.length > 1) {
+ var group = new DGraph.Group();
+ group.headerColor = color;
+ group.fillColor = color;
+ group.alpha = 0.3;
+ group.label = clusterKey;
+ group.mouseup(function (evt) {
+ if (evt.button == 2) {
+ self.currentCluster = this;
+ self.showClusterRightMenu(evt, this);
+ }
+ });
+ self.scene.add(group);
+ self.clusterGroups.push(group);
+ clusterNodes.forEach(function (node) {
+ group.add(node);
+ });
+ this.refresh();
+ }
+ }
+ if (!avoidOverlap) {
+ self.clusterAvoidOverlap(self.clusterGroups);
+ this.refresh();
+ }
+ };
+ VisualGraph.prototype.removeCluster = function () {
+ var self = this;
+ self.clusterGroups = self.clusterGroups.filter(function (clusterGroup) {
+ return clusterGroup != self.currentCluster;
+ });
+ self.scene.remove(self.currentCluster);
+ this.refresh();
+ };
+ VisualGraph.prototype.clearClusters = function () {
+ var self = this;
+ self.clusterGroups.forEach(function (clusterGroup) {
+ self.scene.remove(clusterGroup);
+ });
+ self.clusterGroups = [];
+ this.refresh();
+ };
+ VisualGraph.prototype.clusterAvoidOverlap = function (clusterGroups) {
+ var self = this;
+ var virtualNodes = [];
+ clusterGroups.forEach(function (group, i) {
+ group.ajustSize();
+ var groupRadius = Math.sqrt(
+ (group.width / 2) * (group.width / 2) +
+ (group.height / 2) * (group.height / 2),
+ );
+ var tempNode = new DGraph.Node();
+ tempNode.radius = groupRadius;
+ tempNode.x = group.cx;
+ tempNode.y = group.cy;
+ virtualNodes[i] = tempNode;
+ });
+ if (typeof LayoutFactory != "undefined") {
+ var layout = new LayoutFactory({
+ nodes: virtualNodes,
+ links: null,
+ }).createLayout("noverlap");
+ if (layout != null) {
+ layout.initAlgo();
+ layout.resetConfig({ maxMove: 1 });
+ var times = 0,
+ runFlag = true;
+ while (times++ < 300 && runFlag) {
+ layout.runLayout();
+ runFlag = layout.runFlag;
+ }
+ }
+ }
+ virtualNodes.forEach(function (node, i) {
+ var group = clusterGroups[i];
+ var dx = node.x - group.cx,
+ dy = node.y - group.cy;
+ group.childs.forEach(function (childNode) {
+ childNode.x += dx;
+ childNode.y += dy;
+ });
+ });
+ };
+ VisualGraph.prototype.applyNodeSize = function (range) {
+ var self = this;
+ var minDegree = 0;
+ var maxDegree = 0;
+ self.nodes.forEach(function (n) {
+ var degree = (n.outLinks || []).length + (n.inLinks || []).length;
+ n.degree = degree;
+ minDegree = Math.min(degree, minDegree);
+ maxDegree = Math.max(degree, maxDegree);
+ });
+ var degreesDomain = [Math.sqrt(minDegree), Math.sqrt(maxDegree)];
+ self.nodes.forEach(function (n) {
+ var scale = self.numScale(range, degreesDomain, Math.sqrt(n.degree));
+ n.scaleX = scale;
+ n.scaleY = scale;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.applyLinkWeight = function (range) {
+ var self = this;
+ var minWeight = 3;
+ var maxWeight = 8;
+ self.links.forEach(function (l) {
+ minWeight = Math.min(l.weight, minWeight);
+ maxWeight = Math.max(l.weight, maxWeight);
+ });
+ var weightDomain = [Math.sqrt(minWeight), Math.sqrt(maxWeight)];
+ self.links.forEach(function (l) {
+ var lineWidth = self.numScale(range, weightDomain, Math.sqrt(l.weight));
+ l.lineWidth = Math.round(lineWidth);
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.numScale = function (range, domain, num) {
+ return (
+ ((num - domain[0]) * (range[1] - range[0])) / (domain[1] - domain[0]) +
+ range[0]
+ ).toFixed(1);
+ };
+ VisualGraph.prototype.selectAll = function () {
+ var _self = this;
+ this.nodes.forEach(function (n) {
+ n.selected = true;
+ _self.scene.addToSelected(n);
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.reverseSelect = function () {
+ var _self = this;
+ this.nodes.forEach(function (n) {
+ if (n.selected) {
+ n.selected = false;
+ _self.scene.removeFromSelected(n);
+ } else {
+ n.selected = true;
+ _self.scene.addToSelected(n);
+ }
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.selectRelate = function (node) {
+ var self = this;
+ var _node = node || self.currentNode;
+ if (_node == null) {
+ return false;
+ }
+ var inLinks = _node.inLinks || [];
+ var outLinks = _node.outLinks || [];
+ inLinks.forEach(function (link) {
+ link.source.selected = true;
+ self.scene.addToSelected(link.source);
+ });
+ outLinks.forEach(function (link) {
+ link.target.selected = true;
+ self.scene.addToSelected(link.target);
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.showSelected = function () {
+ this.nodes.forEach(function (n) {
+ if (!n.selected) {
+ n.visible = false;
+ var inLinks = n.inLinks || [],
+ outLinks = n.outLinks || [];
+ inLinks.forEach(function (l) {
+ l.visible = false;
+ });
+ outLinks.forEach(function (l) {
+ l.visible = false;
+ });
+ }
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.setScale = function (node, scale) {
+ if (node) {
+ node.scaleX = scale;
+ node.scaleY = scale;
+ this.refresh();
+ }
+ };
+ VisualGraph.prototype.hideSelected = function () {
+ this.nodes.forEach(function (n) {
+ if (n.selected) {
+ n.visible = false;
+ var inLinks = n.inLinks || [],
+ outLinks = n.outLinks || [];
+ inLinks.forEach(function (l) {
+ l.visible = false;
+ });
+ outLinks.forEach(function (l) {
+ l.visible = false;
+ });
+ }
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.hideIsolatedNodes = function () {
+ this.nodes.forEach(function (n) {
+ if ((n.inLinks || []).length == 0 && (n.outLinks || []).length == 0) {
+ n.visible = false;
+ }
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.showNodes = function () {
+ this.nodes.forEach(function (n) {
+ n.visible = true;
+ n.alpha = 1;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.deleteNodes = function (nodes) {
+ if ((!nodes) instanceof Array || nodes.length == 0) {
+ return;
+ }
+ var self = this;
+ var links = [];
+ var index = -1;
+ nodes.forEach((node) => {
+ (node.inLinks || []).forEach(function (l) {
+ links.push(l);
+ });
+ (node.outLinks || []).forEach(function (l) {
+ links.push(l);
+ });
+ index = self.nodes.indexOf(node);
+ if (index > -1) {
+ self.nodes.splice(index, 1);
+ self.scene.remove(node);
+ }
+ });
+ links.forEach(function (l) {
+ index = self.links.indexOf(l);
+ if (index > -1) {
+ self.links.splice(index, 1);
+ self.scene.remove(l);
+ }
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.deleteNode = function (node) {
+ if (node) {
+ this.deleteNodes([node]);
+ }
+ };
+ VisualGraph.prototype.deleteLinks = function (links) {
+ if ((!links) instanceof Array || links.length == 0) {
+ return;
+ }
+ var self = this;
+ links.forEach((link) => {
+ var index = self.links.indexOf(link);
+ if (index > -1) {
+ self.links.splice(index, 1);
+ self.scene.remove(link);
+ }
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.deleteLink = function (link) {
+ if (link) {
+ this.deleteLinks([link]);
+ }
+ };
+ VisualGraph.prototype.setNodeLabelWithDegree = function (degree) {
+ this.nodes.forEach(function (n) {
+ if ((n.inLinks || []).length + (n.outLinks || []).length >= degree) {
+ n.showlabel = true;
+ } else {
+ n.showlabel = true;
+ n.text = null;
+ }
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.translateOrZoom = function (type) {
+ var self = this;
+ if (type === "zoomOut") {
+ scaleGraph(1.1);
+ } else if (type === "zoomIn") {
+ scaleGraph(0.9);
+ } else {
+ this.stage.centerAndZoom(1.0, 1.0);
+ }
+ this.refresh();
+ function scaleGraph(scale) {
+ var nodeCount = self.nodes.length;
+ var xMean = 0,
+ yMean = 0;
+ self.nodes.forEach(function (n) {
+ xMean += n.x;
+ yMean += n.y;
+ });
+ xMean /= nodeCount;
+ yMean /= nodeCount;
+ self.nodes.forEach(function (n) {
+ var dx = (n.x - xMean) * scale;
+ var dy = (n.y - yMean) * scale;
+ n.x = xMean + dx;
+ n.y = yMean + dy;
+ });
+ }
+ };
+ VisualGraph.prototype.rotateGraph = function (angle) {
+ var self = this;
+ var sin = Math.sin((-angle * Math.PI) / 360);
+ var cos = Math.cos((-angle * Math.PI) / 360);
+ var bounds = this.stage.getBound();
+ var px = Math.round(bounds.width / 2);
+ var py = Math.round(bounds.height / 2);
+ this.nodes.forEach(function (n) {
+ var dx = n.x - px;
+ var dy = n.y - py;
+ n.x = px + dx * cos - dy * sin;
+ n.y = py + dy * cos + dx * sin;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.getGraphStatistic = function () {
+ var self = this;
+ if (self.nodes.length == 0) {
+ return null;
+ }
+ return {
+ nodesCount: self.nodes.length,
+ linksCount: self.links.length,
+ density: self.calculateDensity(),
+ avgDegree: self.calculateAvgDegree(),
+ avgWeightDegree: self.calculateAvgWieghtDegree(),
+ };
+ };
+ VisualGraph.prototype.createMatrix = function (graphVertex, graphAdge) {
+ var n = graphVertex.length;
+ var matrix = [];
+ for (let i = 0; i < n; i++) {
+ let arrTemp = new Array(n);
+ for (let j = 0; j < n; j++) {
+ arrTemp[j] = Infinity;
+ }
+ matrix[i] = arrTemp;
+ }
+ var e = graphAdge.length;
+ for (let i = 0; i < e; i++) {
+ var sourceInx = graphVertex.indexOf(graphAdge[i].source);
+ var targetInx = graphVertex.indexOf(graphAdge[i].target);
+ if (sourceInx === -1 || targetInx === -1) {
+ return;
+ }
+ matrix[sourceInx][targetInx] = graphAdge[i].weight;
+ matrix[targetInx][sourceInx] = graphAdge[i].weight;
+ }
+ return matrix;
+ };
+ VisualGraph.prototype.graphAlgorithm = function () {
+ var vertex = this.nodes.map(function (node) {
+ return node.id;
+ });
+ var edges = this.links.map(function (link) {
+ return { source: link.source.id, target: link.target.id, weight: 1 };
+ });
+ var matrix = this.createMatrix(vertex, edges);
+ var n = vertex.length;
+ var dfsTraverse = function (v) {
+ var visited = [];
+ var result = [];
+ var stack = [];
+ stack.push(v);
+ result.push(v);
+ visited[vertex.indexOf(v)] = true;
+ while (stack.length !== 0) {
+ let p = stack.pop();
+ if (visited[vertex.indexOf(p)] !== true) {
+ result.push(p);
+ }
+ visited[vertex.indexOf(p)] = true;
+ let row = vertex.indexOf(p);
+ for (let i = n - 1; i >= 0; i--) {
+ if (matrix[row][i] !== Infinity && visited[i] !== true) {
+ stack.push(vertex[i]);
+ }
+ }
+ if (result.length > 100) {
+ break;
+ }
+ }
+ return result;
+ };
+ var bfsTraverse = function (v) {
+ var queue = [];
+ var visited = [];
+ var pre = 0,
+ tail = 1;
+ queue.push(v);
+ visited[vertex.indexOf(v)] = true;
+ while (pre !== tail) {
+ let p = queue[pre++];
+ let row = vertex.indexOf(p);
+ for (let i = 0; i < n; i++) {
+ if (matrix[row][i] !== Infinity && visited[i] !== true) {
+ queue.push(vertex[i]);
+ visited[i] = true;
+ }
+ }
+ tail = queue.length;
+ if (pre > 100) {
+ break;
+ }
+ }
+ return queue;
+ };
+ var floyd = function () {
+ var dist = [],
+ path = [];
+ for (let i = 0; i < n; i++) {
+ dist[i] = new Array();
+ path[i] = new Array();
+ for (let j = 0; j < n; j++) {
+ dist[i][j] = matrix[i][j];
+ path[i][j] = [vertex[i]];
+ }
+ }
+ for (let k = 0; k < n; k++) {
+ for (let i = 0; i < n; i++) {
+ for (let j = 0; j < n; j++) {
+ if (dist[i][k] + dist[k][j] < dist[i][j]) {
+ dist[i][j] = dist[i][k] + dist[k][j];
+ path[i][j] = path[i][k].concat(path[k][j]);
+ }
+ if (i === j) {
+ dist[i][j] = 0;
+ }
+ }
+ }
+ }
+ for (let i = 0; i < n; i++) {
+ for (let j = 0; j < n; j++) {
+ path[i][j].push(vertex[j]);
+ }
+ }
+ var out = { dist: dist, path: path };
+ return out;
+ };
+ var dijkstra = function (v) {
+ var dist = [],
+ path = [];
+ for (let i = 0; i < n; i++) {
+ dist[i] = matrix[vertex.indexOf(v)][i];
+ if (dist[i] !== Infinity) {
+ path[i] = [v, vertex[i]];
+ } else {
+ path[i] = [];
+ }
+ }
+ var vis = [];
+ vis[vertex.indexOf(v)] = true;
+ dist[vertex.indexOf(v)] = 0;
+ var num = 1;
+ while (num < n) {
+ let k = 1;
+ for (let i = 0; i < n; i++) {
+ if (vis[i] !== true && dist[k] > dist[i]) {
+ k = i;
+ }
+ }
+ vis[k] = true;
+ for (let i = 0; i < n; i++) {
+ if (dist[i] > dist[k] + matrix[k][i]) {
+ dist[i] = dist[k] + matrix[k][i];
+ path[i] = path[k].concat([vertex[i]]);
+ }
+ }
+ num++;
+ }
+ var out = { dist: dist, path: path };
+ return out;
+ };
+ var bellmanFord = function (source) {
+ let distance = new Map();
+ let paths = new Map();
+ for (let v of vertex) {
+ distance.set(v, Infinity);
+ paths.set(v, []);
+ }
+ distance.set(source, 0);
+ for (let i = 1, len = vertex.length - 1; i < len; i++) {
+ for (let e of edges) {
+ if (distance.get(e.source) + e.weight < distance.get(e.target)) {
+ distance.set(e.target, distance.get(e.source) + e.weight);
+ var pathArr = paths.get(e.target);
+ pathArr = pathArr.concat(paths.get(e.source));
+ pathArr.push(e.source);
+ paths.set(e.target, pathArr);
+ }
+ }
+ }
+ paths.forEach((path, node) => {
+ if (path.length > 0) {
+ path.push(node);
+ }
+ });
+ return { dist: distance, paths: paths };
+ };
+ return {
+ dfsTraverse: dfsTraverse,
+ bfsTraverse: bfsTraverse,
+ floyd: floyd,
+ dijkstra: dijkstra,
+ bellmanFord: bellmanFord,
+ };
+ };
+ VisualGraph.prototype.calculateDensity = function () {
+ var self = this;
+ var nodesCount = self.nodes.length,
+ linksCount = self.links.length;
+ var multiplier = 1;
+ if (!self.isDerictedGraph) {
+ multiplier = 2;
+ }
+ var density =
+ (multiplier * linksCount) / (nodesCount * nodesCount - nodesCount);
+ return density.toFixed(4);
+ };
+ VisualGraph.prototype.calculateAvgDegree = function () {
+ var self = this;
+ var nodesCount = self.nodes.length,
+ averageDegree = 0;
+ self.nodes.forEach(function (n) {
+ averageDegree += (n.inLinks || []).length + (n.outLinks || []).length;
+ });
+ var multiplier = 1;
+ if (self.isDerictedGraph) {
+ multiplier = 2;
+ }
+ var avgDegree = (averageDegree /= multiplier * nodesCount);
+ return avgDegree.toFixed(4);
+ };
+ VisualGraph.prototype.calculateDarmity = function () {
+ var self = this;
+ let darmity = 0;
+ var algo = self.graphAlgorithm();
+ var distArr = algo.floyd().dist;
+ distArr.forEach((distLine) => {
+ distLine.forEach((dist) => {
+ darmity = Math.max(dist, darmity);
+ });
+ });
+ return darmity;
+ };
+ VisualGraph.prototype.avgClusterCoefficient = function () {
+ var self = this;
+ if (self.nodes.length == 0) {
+ return 0;
+ }
+ let clusterCoefficient = 0;
+ self.nodes.forEach(function (node) {
+ clusterCoefficient += self.clusterCoefficient(node);
+ });
+ return (clusterCoefficient / self.nodes.length).toFixed(4);
+ };
+ VisualGraph.prototype.avgPathLength = function () {
+ var self = this;
+ if (self.nodes.length == 0) {
+ return 0;
+ }
+ var totalPath = 0;
+ var pathNum = 0;
+ var algo = self.graphAlgorithm();
+ var distArr = algo.floyd().dist;
+ distArr.forEach((distLine) => {
+ distLine.forEach((dist) => {
+ if (dist !== Infinity && dist > 0) {
+ pathNum++;
+ totalPath += dist;
+ }
+ });
+ });
+ return (totalPath / pathNum).toFixed(4);
+ };
+ VisualGraph.prototype.calculateAvgWieghtDegree = function () {
+ var self = this;
+ var nodesCount = self.nodes.length,
+ averageWeightDegree = 0;
+ self.nodes.forEach(function (n) {
+ if (self.isDerictedGraph) {
+ (n.inLinks || []).forEach(function (l) {
+ averageWeightDegree += l.weight;
+ });
+ (n.outLinks || []).forEach(function (l) {
+ averageWeightDegree += l.weight;
+ });
+ } else {
+ var allLinks = [];
+ allLinks.push(n.inLinks || []);
+ allLinks.push(n.outLinks || []);
+ allLinks.forEach(function (l) {
+ var multi = 1;
+ if (l.source == l.target) {
+ multi = 2;
+ }
+ averageWeightDegree += multi * l.weight;
+ });
+ }
+ });
+ var multiplier = 1;
+ if (self.isDerictedGraph) {
+ multiplier = 2;
+ }
+ var avgDegree = (averageWeightDegree /= multiplier * nodesCount);
+ return avgDegree.toFixed(4);
+ };
+ VisualGraph.prototype.closenessCentrality = function (node, type) {
+ var self = this;
+ let sumShortPath = 0;
+ var algo = self.graphAlgorithm();
+ var shortPaths = algo.dijkstra(node.id);
+ shortPaths.dist.forEach((pathLength) => {
+ if (pathLength !== Infinity) {
+ sumShortPath += pathLength;
+ }
+ });
+ var closeness = (self.nodes.length - 1) / sumShortPath;
+ return closeness;
+ };
+ VisualGraph.prototype.degreeCentrality = function (node) {
+ var self = this;
+ var nodeNum = self.nodes.length;
+ if (nodeNum == 1) {
+ return 0;
+ }
+ var degreeCentrality =
+ ((node.outLinks || []).length + (node.inLinks || []).length) /
+ (nodeNum - 1);
+ return degreeCentrality;
+ };
+ VisualGraph.prototype.clusterCoefficient = function (node) {
+ var self = this;
+ var nodeIdSet = new Set();
+ var outNeiberNodes = (node.outLinks || []).map((link) => {
+ return link.target;
+ });
+ var inNeiberNodes = (node.inLinks || []).map((link) => {
+ return link.source;
+ });
+ var allNeiberNodes = outNeiberNodes.concat(inNeiberNodes);
+ allNeiberNodes.forEach((_node) => {
+ if (_node.id != node.id) {
+ nodeIdSet.add(_node.id);
+ }
+ });
+ var allNeiberLinkSet = new Set();
+ allNeiberNodes.forEach((_node) => {
+ var outLinks = (_node.outLinks || []).filter((_link) => {
+ return _link.target.id != node.id && _link.source != _link.target;
+ });
+ var nodeIdStr1 = null,
+ nodeIdStr2 = null;
+ outLinks.forEach((_link) => {
+ if (nodeIdSet.has(_link.source.id) && nodeIdSet.has(_link.target.id)) {
+ nodeIdStr1 = _link.source.id + ":" + _link.target.id;
+ nodeIdStr2 = _link.target.id + ":" + _link.source.id;
+ if (
+ !allNeiberLinkSet.has(nodeIdStr1) &&
+ !allNeiberLinkSet.has(nodeIdStr2)
+ ) {
+ allNeiberLinkSet.add(nodeIdStr1);
+ }
+ }
+ });
+ var inLinks = (_node.inLinks || []).filter((_link) => {
+ return _link.source.id != node.id && _link.source != _link.target;
+ });
+ inLinks.forEach((_link) => {
+ if (nodeIdSet.has(_link.source.id) && nodeIdSet.has(_link.target.id)) {
+ nodeIdStr1 = _link.source.id + ":" + _link.target.id;
+ nodeIdStr2 = _link.target.id + ":" + _link.source.id;
+ if (
+ !allNeiberLinkSet.has(nodeIdStr1) &&
+ !allNeiberLinkSet.has(nodeIdStr2)
+ ) {
+ allNeiberLinkSet.add(nodeIdStr1);
+ }
+ }
+ });
+ });
+ var edgeNum = allNeiberLinkSet.size;
+ var ck12 = nodeIdSet.size * (nodeIdSet.size - 1);
+ var clusterCoefficient = 0;
+ if (ck12 > 0) {
+ clusterCoefficient = edgeNum / ck12;
+ }
+ return clusterCoefficient;
+ };
+ VisualGraph.prototype.edgeBetweennessCentrality = function (edge) {
+ var self = this;
+ let allShortPath = 0;
+ let processShortPath = 0;
+ var sourceId = edge.source.id;
+ var targetId = edge.target.id;
+ var algo = self.graphAlgorithm();
+ var paths = algo.floyd().path;
+ var arrLength = 0,
+ startNodeId = null,
+ endNodeId = null;
+ var sourceNodeIndx, targetNodeIndx;
+ paths.forEach((pathArr) => {
+ pathArr.forEach((path) => {
+ arrLength = path.length;
+ startNodeId = path[0];
+ endNodeId = path[arrLength - 1];
+ if (startNodeId != endNodeId) {
+ allShortPath++;
+ sourceNodeIndx = path.indexOf(sourceId);
+ targetNodeIndx = path.indexOf(targetId);
+ if (
+ sourceNodeIndx != -1 &&
+ targetNodeIndx != -1 &&
+ sourceNodeIndx + 1 == targetNodeIndx
+ ) {
+ processShortPath++;
+ }
+ }
+ });
+ });
+ if (allShortPath == 0) {
+ return 0;
+ }
+ return (processShortPath / allShortPath) * 2;
+ };
+ VisualGraph.prototype.rankEdgeBetweennessCentrality = function () {
+ var self = this;
+ var algo = self.graphAlgorithm();
+ var paths = algo.floyd().path;
+ var edges = self.links.map(function (link) {
+ if (!link.id) {
+ link.id = link.source.id + "@" + link.target.id;
+ }
+ return link;
+ });
+ edges.forEach((edge) => {
+ var allShortPath = 0;
+ var processShortPath = 0;
+ var sourceId = edge.source.id;
+ var targetId = edge.target.id;
+ var arrLength = 0,
+ startNodeId = null,
+ endNodeId = null;
+ var sourceNodeIndx, targetNodeIndx;
+ paths.forEach((pathArr) => {
+ pathArr.forEach((path) => {
+ arrLength = path.length;
+ startNodeId = path[0];
+ endNodeId = path[arrLength - 1];
+ if (startNodeId != endNodeId) {
+ allShortPath++;
+ sourceNodeIndx = path.indexOf(sourceId);
+ targetNodeIndx = path.indexOf(targetId);
+ if (
+ sourceNodeIndx != -1 &&
+ targetNodeIndx != -1 &&
+ sourceNodeIndx + 1 == targetNodeIndx
+ ) {
+ processShortPath++;
+ }
+ }
+ });
+ });
+ if (allShortPath == 0) {
+ edge.betweennessCentrality = 0;
+ } else {
+ edge.betweennessCentrality = (processShortPath / allShortPath) * 2;
+ }
+ });
+ edges.sort(function (edge1, edge2) {
+ return edge2.betweennessCentrality - edge1.betweennessCentrality;
+ });
+ return edges;
+ };
+ VisualGraph.prototype.serialized = function () {
+ var self = this;
+ var _graph = { nodes: [], links: [] };
+ self.nodes.forEach(function (n) {
+ _graph.nodes.push({
+ id: n.id,
+ label: n.label,
+ x: Math.round(n.x),
+ y: Math.round(n.y),
+ width: n.width,
+ height: n.height,
+ size: n.size,
+ color: n.fillColor,
+ shape: n.shape,
+ });
+ });
+ self.links.forEach(function (l) {
+ _graph.links.push({
+ id: l.id,
+ source: l.source.id,
+ target: l.target.id,
+ label: l.label || l.type || "",
+ lineWidth: l.lineWidth,
+ lineType: l.lineType,
+ color: l.strokeColor,
+ });
+ });
+ return _graph;
+ };
+ VisualGraph.prototype.nodeWrapText = function (flag) {
+ this.nodes.forEach((node) => {
+ node.wrapText = flag;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.nodeMapAlphaByDegree = function () {
+ var self = this;
+ var minDegree = 0,
+ maxDegree = 0;
+ self.nodes.forEach(function (n) {
+ n.outdegree = (n.outLinks || []).reduce(function (total, _link) {
+ return total + (_link.weight || 1);
+ }, 0);
+ n.indegree = (n.inLinks || []).reduce(function (total, _link) {
+ return total + (_link.weight || 1);
+ }, 0);
+ n.degree = n.outdegree + n.indegree;
+ minDegree = Math.min(n.degree, minDegree);
+ maxDegree = Math.max(n.degree, maxDegree);
+ });
+ var degreesDomain = [minDegree, maxDegree];
+ var range = [0.2, 1];
+ self.nodes.forEach(function (n) {
+ var _alpha = self.numScale(range, degreesDomain, n.degree);
+ n.alpha = _alpha;
+ (n.outLinks || []).forEach(function (l) {
+ l.alpha = _alpha;
+ });
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.nodeMapSizeByDegree = function (propType, range) {
+ var self = this;
+ var minDegree = 0,
+ maxDegree = 0;
+ var degreeArr = {};
+ self.nodes.forEach(function (n) {
+ n.outdegree = (n.outLinks || []).reduce(function (total, _link) {
+ return total + (_link.weight || 1);
+ }, 0);
+ n.indegree = (n.inLinks || []).reduce(function (total, _link) {
+ return total + (_link.weight || 1);
+ }, 0);
+ n.degree = n.outdegree + n.indegree;
+ if (propType == "degree") {
+ minDegree = Math.min(n.degree, minDegree);
+ maxDegree = Math.max(n.degree, maxDegree);
+ } else if (propType == "outdegree") {
+ minDegree = Math.min(n.outdegree, minDegree);
+ maxDegree = Math.max(n.outdegree, maxDegree);
+ } else {
+ minDegree = Math.min(n.indegree, minDegree);
+ maxDegree = Math.max(n.indegree, maxDegree);
+ }
+ });
+ var degreesDomain = [minDegree, maxDegree];
+ self.nodes.forEach(function (n) {
+ var nodeSize = 1;
+ if (propType == "degree") {
+ nodeSize = self.numScale(range, degreesDomain, n.degree);
+ } else if (propType == "outdegree") {
+ nodeSize = self.numScale(range, degreesDomain, n.outdegree);
+ } else {
+ nodeSize = self.numScale(range, degreesDomain, n.indegree);
+ }
+ n.width = n.height = n.radius = Math.round(nodeSize);
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.findAllPath = function (
+ startNode,
+ endNode,
+ isDirected,
+ ) {
+ var self = this;
+ if (!startNode || !endNode) {
+ return [];
+ }
+ let nodeVisited = new Map();
+ let allPathNodes = [];
+ const findPath = (source, target, pathNodes = []) => {
+ pathNodes = [...pathNodes];
+ pathNodes.push(source);
+ if (source === target) {
+ allPathNodes.push(pathNodes);
+ return;
+ }
+ const neighborNodes = [];
+ (source.outLinks || []).forEach((link) => {
+ if (neighborNodes.indexOf(link.target) == -1 && source != link.target) {
+ neighborNodes.push(link.target);
+ }
+ });
+ if (!isDirected) {
+ (source.inLinks || []).forEach((link) => {
+ if (
+ neighborNodes.indexOf(link.source) == -1 &&
+ source != link.source
+ ) {
+ neighborNodes.push(link.source);
+ }
+ });
+ }
+ for (let i = 0; i < neighborNodes.length; i++) {
+ var node = neighborNodes[i];
+ if (pathNodes.indexOf(node) == -1) {
+ findPath(node, target, pathNodes);
+ }
+ }
+ };
+ findPath(startNode, endNode);
+ allPathNodes.sort((path1, path2) => {
+ return path1.length - path2.length;
+ });
+ let allPathLinks = [];
+ allPathNodes.forEach((pathNodes) => {
+ var paths = [];
+ var length = pathNodes.length;
+ for (var i = 0; i < length; i++) {
+ var pathNode = pathNodes[i];
+ (pathNode.outLinks || []).forEach((link) => {
+ if (
+ pathNodes.indexOf(link.target) != -1 &&
+ pathNodes.indexOf(link.source) != -1 &&
+ paths.indexOf(link) == -1
+ ) {
+ paths.push(link);
+ }
+ });
+ (pathNode.inLinks || []).forEach((link) => {
+ if (
+ pathNodes.indexOf(link.target) != -1 &&
+ pathNodes.indexOf(link.source) != -1 &&
+ paths.indexOf(link) == -1
+ ) {
+ paths.push(link);
+ }
+ });
+ }
+ allPathLinks.push(paths);
+ });
+ return allPathLinks;
+ };
+ VisualGraph.prototype.findShortPath = function (
+ sourceId,
+ targetId,
+ direction,
+ ) {
+ var self = this;
+ var startNode = self.nodes.filter(function (n) {
+ return n.id == sourceId;
+ })[0];
+ var endNode = self.nodes.filter(function (n) {
+ return n.id == targetId;
+ })[0];
+ let allPathLinks = [];
+ if (direction == "source") {
+ allPathLinks = self.findAllPath(startNode, endNode, true);
+ } else if (direction == "target") {
+ allPathLinks = self.findAllPath(endNode, startNode, true);
+ } else {
+ allPathLinks = self.findAllPath(startNode, endNode, false);
+ }
+ var shortPaths = [];
+ if (allPathLinks.length > 0) {
+ var shortestPathLength = allPathLinks[0].length;
+ shortPaths = allPathLinks.filter((pathArr) => {
+ return pathArr.length == shortestPathLength;
+ });
+ shortPaths.forEach((paths) => {
+ paths.forEach((link) => {
+ self.selectedEdge(link);
+ });
+ });
+ self.refresh();
+ }
+ return shortPaths;
+ };
+ VisualGraph.prototype.pathAnalyze = function (sourceId, targetId, direction) {
+ var self = this;
+ if (sourceLabel.length == 0 || targetLabel.length == 0) {
+ return null;
+ }
+ var startNode = self.nodes.filter(function (n) {
+ return n.id == sourceId;
+ })[0];
+ var endNode = self.nodes.filter(function (n) {
+ return n.id == targetId;
+ })[0];
+ let allPathLinks = [];
+ if (direction == "source") {
+ allPathLinks = self.findAllPath(startNode, endNode, true);
+ } else if (direction == "target") {
+ allPathLinks = self.findAllPath(endNode, startNode, true);
+ } else {
+ allPathLinks = self.findAllPath(startNode, endNode, false);
+ }
+ if (allPathLinks.length > 0) {
+ allPathLinks.forEach((path) => {
+ path.forEach((link) => {
+ self.selectedEdge(link);
+ });
+ });
+ self.refresh();
+ }
+ return allPathLinks;
+ };
+ VisualGraph.prototype.selectedEdge = function (link) {
+ if (link) {
+ link.selected = true;
+ this.scene.addToSelected(link);
+ link.target.selected = true;
+ this.scene.addToSelected(link.target);
+ link.source.selected = true;
+ this.scene.addToSelected(link.source);
+ }
+ };
+ VisualGraph.prototype.checkAllCycle = function () {
+ var self = this;
+ var lgDegreeNodes = self.nodes.filter((node) => {
+ return (
+ (node.inLinks || []).length >= 1 && (node.outLinks || []).length >= 1
+ );
+ });
+ if (!lgDegreeNodes) {
+ return null;
+ }
+ let allCyclePath = [];
+ var length = lgDegreeNodes.length;
+ for (let i = 0; i < length; i++) {
+ var startNode = lgDegreeNodes[i];
+ var inLinks = startNode.inLinks;
+ inLinks.forEach((link) => {
+ var targetNode = link.source;
+ if (lgDegreeNodes.indexOf(targetNode) != -1) {
+ var allPathLinks = self.findAllPath(startNode, targetNode, true);
+ if (allPathLinks && allPathLinks.length > 0) {
+ allCyclePath = allCyclePath.concat(allPathLinks);
+ }
+ }
+ });
+ }
+ let resultPath = [];
+ allCyclePath.forEach((paths) => {
+ paths.forEach((path) => {
+ if (resultPath.indexOf(path) == -1) {
+ resultPath.push(path);
+ }
+ });
+ });
+ resultPath.forEach((link) => {
+ self.selectedEdge(link);
+ });
+ self.refresh();
+ return resultPath;
+ };
+ VisualGraph.prototype.findNodeCyclePath = function (node) {
+ var self = this;
+ if (!node) {
+ return null;
+ }
+ let allCyclePath = [];
+ var inLinks = node.inLinks || [];
+ inLinks.forEach((link) => {
+ var targetNode = link.source;
+ var allPathLinks = self.findAllPath(node, targetNode, true);
+ if (allPathLinks && allPathLinks.length > 0) {
+ allCyclePath = allCyclePath.concat(allPathLinks);
+ }
+ });
+ let resultPath = [];
+ allCyclePath.forEach((paths) => {
+ paths.forEach((path) => {
+ if (resultPath.indexOf(path) == -1) {
+ resultPath.push(path);
+ }
+ });
+ });
+ resultPath.forEach((link) => {
+ self.selectedEdge(link);
+ });
+ self.refresh();
+ return resultPath;
+ };
+ VisualGraph.prototype.findClusters = function () {
+ var _self = this;
+ var nodeList = [];
+ this.nodes.forEach(function (n) {
+ if ((n.outLinks || []).length > 0) {
+ n.selected = true;
+ _self.scene.addToSelected(n);
+ nodeList.push(n);
+ }
+ });
+ this.refresh();
+ return nodeList;
+ };
+ VisualGraph.prototype.findNDegreeRelates = function (degree) {
+ var _self = this;
+ var nodeList = [];
+ this.nodes.forEach(function (n) {
+ var total = (n.inLinks || []).length + (n.outLinks || []).length;
+ if (total >= degree) {
+ n.selected = true;
+ _self.scene.addToSelected(n);
+ nodeList.push(n);
+ }
+ });
+ this.refresh();
+ return nodeList;
+ };
+ VisualGraph.prototype.nLayerRelates = function (nodeLabel, layerNum) {
+ var _self = this;
+ var currentNode = _self.nodes.filter(function (n) {
+ return n.label == nodeLabel;
+ })[0];
+ var middleNode = [];
+ var nowOutsideNode = {};
+ var nodeList = [];
+ if (null != currentNode) {
+ currentNode.selected = true;
+ _self.scene.addToSelected(currentNode);
+ nodeList.push(currentNode);
+ recursive(currentNode, layerNum);
+ _self.refresh();
+ }
+ function recursive(node, nLayer) {
+ if (nLayer > 1) {
+ if (layerNum == nLayer && middleNode.indexOf(node) == -1) {
+ middleNode.push(node);
+ }
+ var level = layerNum - nLayer;
+ var inLinks = node.inLinks || [];
+ var outLinks = node.outLinks || [];
+ inLinks.forEach(function (l) {
+ if (middleNode.indexOf(l.source) == -1) {
+ middleNode.push(l.source);
+ if (nowOutsideNode[level] == undefined) {
+ nowOutsideNode[level] = [];
+ }
+ nowOutsideNode[level].push(l.source);
+ }
+ });
+ outLinks.forEach(function (l) {
+ if (middleNode.indexOf(l.target) == -1) {
+ middleNode.push(l.target);
+ if (nowOutsideNode[level] == undefined) {
+ nowOutsideNode[level] = [];
+ }
+ nowOutsideNode[level].push(l.target);
+ }
+ });
+ if (nowOutsideNode[level] == undefined) {
+ return;
+ }
+ nowOutsideNode[level].forEach(function (l) {
+ recursive(l, nLayer - 1);
+ });
+ } else if (nLayer == 1) {
+ var inLinks = node.inLinks || [];
+ var outLinks = node.outLinks || [];
+ inLinks.forEach(function (l) {
+ if (middleNode.indexOf(l.source) == -1) {
+ l.source.selected = true;
+ _self.scene.addToSelected(l.source);
+ nodeList.push(l.source);
+ }
+ });
+ outLinks.forEach(function (l) {
+ if (middleNode.indexOf(l.target) == -1) {
+ l.target.selected = true;
+ _self.scene.addToSelected(l.target);
+ nodeList.push(l.target);
+ }
+ });
+ }
+ }
+ return nodeList;
+ };
+ VisualGraph.prototype.removeCurrentLink = function () {
+ this.scene.remove(this.currentLink);
+ this.currentLink = null;
+ this.refresh();
+ };
+ VisualGraph.prototype.filterNodes = function (type, condition, value) {
+ this.nodes.forEach(function (n) {
+ var degree = 0;
+ if (type == "degree") {
+ degree = (n.inLinks || []).length + (n.outLinks || []).length;
+ } else if (type == "outdegree") {
+ degree = (n.outLinks || []).length;
+ } else if (type == "indegree") {
+ degree = (n.inLinks || []).length;
+ }
+ if (condition == 1) {
+ if (degree > value) {
+ n.visible = true;
+ } else {
+ n.visible = false;
+ }
+ } else if (condition == 2) {
+ if (degree == value) {
+ n.visible = true;
+ } else {
+ n.visible = false;
+ }
+ } else if (condition == 3) {
+ if (degree < value) {
+ n.visible = true;
+ } else {
+ n.visible = false;
+ }
+ }
+ });
+ this.links.forEach(function (l) {
+ if (l.source.visible == false || l.target.visible == false) {
+ l.visible = false;
+ } else {
+ l.visible = true;
+ }
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.filterLinks = function (condition, value) {
+ this.links.forEach(function (l) {
+ if (l.source.visible == true && l.target.visible == true) {
+ if (condition == 1) {
+ if (l.weight > value) {
+ l.visible = true;
+ } else {
+ l.visible = false;
+ }
+ } else if (condition == 2) {
+ if (l.weight == value) {
+ l.visible = true;
+ } else {
+ l.visible = false;
+ }
+ } else if (condition == 3) {
+ if (l.weight < value) {
+ l.visible = true;
+ } else {
+ l.visible = false;
+ }
+ }
+ } else {
+ l.visible = false;
+ }
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.nodeMapColorsByDegree = function (propType, colorArr) {
+ var self = this;
+ var degreeArr = {};
+ self.nodes.forEach(function (n) {
+ n.outdegree = (n.outLinks || []).length;
+ n.indegree = (n.inLinks || []).length;
+ n.degree = n.outdegree + n.indegree;
+ if (propType == "degree") {
+ degreeArr[n.degree + ""] = 1;
+ } else if (propType == "outdegree") {
+ degreeArr[n.outdegree + ""] = 1;
+ } else {
+ degreeArr[n.indegree + ""] = 1;
+ }
+ });
+ var degrees = [];
+ for (var d in degreeArr) {
+ degrees.push(d);
+ }
+ degrees.sort(function (d1, d2) {
+ return Number(d2) - Number(d1);
+ });
+ var ctool = new DGraph.ColorUtils();
+ var colors = ctool.generateGradientColor(
+ colorArr[0],
+ colorArr[1],
+ degrees.length,
+ );
+ self.nodes.forEach(function (n) {
+ var position = 0;
+ if (propType == "degree") {
+ position = degrees.indexOf(n.degree + "");
+ } else if (propType == "outdegree") {
+ position = degrees.indexOf(n.outdegree + "");
+ } else {
+ position = degrees.indexOf(n.indegree + "");
+ }
+ n.fillColor = colors[position].replace("rgb(", "").replace(")", "");
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.setLineDirected = function (isDirect) {
+ this.links.forEach(function (l) {
+ l.showArrow = isDirect;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.setLineDashed = function (isDashed) {
+ var self = this;
+ var dashed = [0];
+ if (isDashed) {
+ dashed = [8, 5];
+ }
+ this.links.forEach(function (l) {
+ l.lineDash = dashed;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.setNodeSize = function (nodeSize) {
+ nodeSize = Number(nodeSize) || 60;
+ this.config.node.size = nodeSize;
+ this.nodes.forEach(function (node) {
+ node.width = node.height = Math.round(nodeSize);
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.setNodeColor = function (hexColor) {
+ var rgbColor = this.converHexToRGB(hexColor);
+ this.defaultNodeColor = rgbColor;
+ this.nodes.forEach(function (node) {
+ node.fillColor = rgbColor;
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.covertSencePoint = function (event) {
+ return DGraph.util.getEventPosition(event);
+ };
+ VisualGraph.prototype.getMouseDownPosition = function () {
+ var self = this;
+ return { x: self.scene.mouseDownX, y: self.scene.mouseDownY };
+ };
+ VisualGraph.prototype.getPagePosition = function (x, y) {
+ if (arguments.length != 2) {
+ return { pageX: 0, pageY: 0 };
+ }
+ return this.stage.getPagePosition(x, y);
+ };
+ VisualGraph.prototype.getMousePosition = function (event) {
+ var p = DGraph.util.getEventPosition(event);
+ return { x: p.x, y: p.y };
+ };
+ VisualGraph.prototype.addNodeForDrag = function (_node, callback) {
+ var self = this;
+ self.stage.removeEventListener("mousemove");
+ self.stage.mousemove(function (event) {
+ var p = self.scene.toSceneEvent(event);
+ self.stage.removeEventListener("mousemove");
+ _node.id = _node.id == null ? self.nodeIdIndex++ : _node.id;
+ _node.x = p.x;
+ _node.y = p.y;
+ var node = self.newNode(_node);
+ node.fixed = true;
+ self.nodes.push(node);
+ self.scene.add(node);
+ self.refresh();
+ if (callback && typeof callback === "function") {
+ callback(node);
+ }
+ });
+ };
+ VisualGraph.prototype.showAll = function () {
+ this.nodes.forEach(function (n) {
+ if (!n.visible) {
+ n.visible = true;
+ }
+ });
+ this.links.forEach(function (l) {
+ if (!l.visible) {
+ l.visible = true;
+ }
+ });
+ this.refresh();
+ };
+ VisualGraph.prototype.filterChangeVisible = function (
+ entityFalse,
+ linkFalse,
+ infoFilterParams,
+ ) {
+ var _self = this;
+ _self.showAll();
+ if (entityFalse.length > 0) {
+ _self.nodes.forEach(function (n) {
+ if (n.type && entityFalse.indexOf(n.type) != -1) {
+ n.visible = false;
+ }
+ });
+ }
+ if (linkFalse.length > 0) {
+ _self.links.forEach(function (l) {
+ if (l.label && linkFalse.indexOf(l.label) != -1) {
+ l.visible = false;
+ }
+ });
+ }
+ if (infoFilterParams["linkCount"]) {
+ var _compare = infoFilterParams["linkCount"][0];
+ var _input = infoFilterParams["linkCount"][1];
+ _self.nodes.forEach(function (n) {
+ var degree = (n.inLinks || []).length + (n.outLinks || []).length;
+ if (!showOrHide(_compare, _input, degree)) {
+ n.visible = false;
+ }
+ });
+ }
+ if (infoFilterParams["linkOut"]) {
+ var _compare = infoFilterParams["linkOut"][0];
+ var _input = infoFilterParams["linkOut"][1];
+ _self.nodes.forEach(function (n) {
+ var degree = (n.outLinks || []).length;
+ if (!showOrHide(_compare, _input, degree)) {
+ n.visible = false;
+ }
+ });
+ }
+ if (infoFilterParams["linkIn"]) {
+ var _compare = infoFilterParams["linkIn"][0];
+ var _input = infoFilterParams["linkIn"][1];
+ _self.nodes.forEach(function (n) {
+ var degree = (n.inLinks || []).length;
+ if (!showOrHide(_compare, _input, degree)) {
+ n.visible = false;
+ }
+ });
+ }
+ if (infoFilterParams["linkWeight"]) {
+ var _compare = infoFilterParams["linkWeight"][0];
+ var _input = infoFilterParams["linkWeight"][1];
+ _self.links.forEach(function (l) {
+ if (!showOrHide(_compare, _input, l.weight)) {
+ l.visible = false;
+ }
+ });
+ }
+ if (infoFilterParams["entityDesc"]) {
+ var _compare = infoFilterParams["entityDesc"][0];
+ var _input = infoFilterParams["entityDesc"][1];
+ _self.nodes.forEach(function (n) {
+ var nodeValue = n.label;
+ if (_compare == 1) {
+ if (nodeValue != _input) {
+ n.visible = false;
+ }
+ } else if (_compare == 2) {
+ if (nodeValue.indexOf(_input) == -1) {
+ n.visible = false;
+ }
+ }
+ });
+ }
+ _self.links.forEach(function (l) {
+ if (!l.source.visible || !l.target.visible) {
+ l.visible = false;
+ }
+ });
+ _self.refresh();
+ function showOrHide(_compareType, compareValue, _degree) {
+ if (_compareType == 1) {
+ if (_degree > compareValue) {
+ return true;
+ }
+ return false;
+ } else if (_compareType == 2) {
+ if (_degree == compareValue) {
+ return true;
+ }
+ return false;
+ } else {
+ if (_degree < compareValue) {
+ return true;
+ }
+ return false;
+ }
+ return true;
+ }
+ };
+ VisualGraph.prototype.delSelect = function () {
+ var _self = this;
+ var selectNodes = _self.nodes.filter((n) => {
+ return n.selected;
+ });
+ selectNodes.forEach((n) => {
+ _self.removeOneNode(n);
+ });
+ };
+ VisualGraph.prototype.removeOneNode = function (node) {
+ var _self = this;
+ if (node) {
+ var links = [];
+ var index = _self.nodes.indexOf(node);
+ if (index > -1) {
+ (node.inLinks || []).forEach(function (l) {
+ links.push(l);
+ });
+ (node.outLinks || []).forEach(function (l) {
+ links.push(l);
+ });
+ _self.scene.remove(node);
+ _self.nodes.splice(index, 1);
+ }
+ links.forEach(function (l) {
+ index = _self.links.indexOf(l);
+ if (index > -1) {
+ _self.scene.remove(l);
+ _self.links.splice(index, 1);
+ }
+ });
+ node = null;
+ _self.refresh();
+ }
+ };
+ VisualGraph.prototype.clearAll = function () {
+ if (this.scene) {
+ this.scene.clear();
+ }
+ this.nodes = [];
+ this.links = [];
+ this.nodeIdIndex = 1;
+ this.currentNode = null;
+ this.currentLink = null;
+ this.currentLayout = null;
+ this.clusterGroups = [];
+ this.currentCluster = null;
+ this.drawLinkFlag = false;
+ this.virLink = null;
+ this.setZoom("zoom1");
+ this.stopRunningLayout(10);
+ this.refresh();
+ };
+ VisualGraph.prototype.destroy = function () {
+ this.clearAll();
+ this.scene.removeAllEventListener();
+ this.stage.removeAllEventListener();
+ };
+ VisualGraph.prototype.rightMenuOprate = function (optType) {
+ var self = this;
+ switch (optType) {
+ case "allSelect":
+ self.selectAll();
+ break;
+ case "rebackSel":
+ self.reverseSelect();
+ break;
+ case "showAll":
+ self.showAll();
+ break;
+ case "selRelate":
+ self.selectRelate();
+ break;
+ case "showNodes":
+ self.showNodes();
+ break;
+ case "showSelNode":
+ self.showSelected();
+ break;
+ case "hideSelNode":
+ self.hideSelected();
+ break;
+ case "delSelect":
+ self.delSelect();
+ break;
+ case "clearAll":
+ this.clearAll();
+ break;
+ case "hideIsolatedNodes":
+ self.hideIsolatedNodes();
+ break;
+ case "showLinks":
+ self.showAllLink();
+ break;
+ case "hideLinks":
+ self.hideAllLink();
+ break;
+ case "sourcelphaMap":
+ self.nodeMapAlphaByDegree();
+ break;
+ case "saveImage":
+ self.saveImage();
+ break;
+ case "deleteNode":
+ self.deleteNode(self.currentNode);
+ self.currentNode = null;
+ break;
+ case "nodeConnent":
+ self.beginAddLine();
+ break;
+ case "delEdge":
+ self.deleteLink(self.currentLink);
+ self.currentLink = null;
+ break;
+ case "expanded":
+ self.expanded(self.currentNode);
+ break;
+ case "contract":
+ self.contract(self.currentNode);
+ break;
+ case "directedLine":
+ self.setLineDirected(true);
+ break;
+ case "undirectedLine":
+ self.setLineDirected(false);
+ break;
+ case "showLineLabel":
+ self.showLinkLabel(true);
+ break;
+ case "hideLineLabel":
+ self.showLinkLabel(false);
+ break;
+ case "Rline":
+ self.setLineDashed(false);
+ break;
+ case "Vline":
+ self.setLineDashed(true);
+ break;
+ default:
+ break;
+ }
+ };
+ VisualGraph.prototype.beginAddLine = function (callback) {
+ this.drawLinkFlag = true;
+ if (callback && typeof callback === "function") {
+ this.drawLineCallback = callback;
+ }
+ };
+ VisualGraph.prototype.drawVirtualLine = function (nodeA, nodeB) {
+ var self = this;
+ var line = self.newEdge(nodeA, nodeB);
+ self.scene.add(line);
+ return line;
+ };
+ VisualGraph.prototype.drawVirtualNode = function (config) {
+ var self = this;
+ var node = self.newNode(config || { x: 10, y: 10, width: 5 });
+ node.dragable = false;
+ node.fixed = true;
+ self.scene.add(node);
+ return node;
+ };
+ VisualGraph.prototype.removeLine = function (line) {
+ this.scene.remove(line);
+ this.refresh();
+ };
+ VisualGraph.prototype.computeParentAngle = function (node) {
+ node = node || {};
+ var angleRadian = 0;
+ var parentNodes = [],
+ parentFlag = true;
+ (node.inLinks || []).forEach(function (l) {
+ parentNodes.push(l.source);
+ });
+ if (parentNodes.length == 0) {
+ parentFlag = false;
+ (node.outLinks || []).forEach(function (l) {
+ parentNodes.push(l.target);
+ });
+ }
+ var maxParentNode;
+ maxParentNode = parentNodes.sort(function (n1, n2) {
+ if (parentFlag) {
+ return (
+ (n1.outLinks || []).length + (n1.inLinks || []).length <
+ (n2.outLinks || []).length + (n2.inLinks || []).length
+ );
+ } else {
+ return (
+ (n1.outLinks || []).length + (n1.inLinks || []).length >
+ (n2.outLinks || []).length + (n2.inLinks || []).length
+ );
+ }
+ })[0];
+ if (maxParentNode) {
+ var xp = maxParentNode.cx,
+ yp = maxParentNode.cy;
+ var x0 = node.cx,
+ y0 = node.cy;
+ angleRadian = Math.atan2(y0 - yp, x0 - xp);
+ }
+ return angleRadian;
+ };
+ VisualGraph.prototype.activeAddNodeLinks = function (_nodes, _links) {
+ var _self = this;
+ _self.incremaNodesCodinate(_nodes);
+ var newNodes = [],
+ newLinks = [];
+ (_nodes || []).forEach(function (_node, i) {
+ var hasNodes = _self.nodes.filter(function (n) {
+ return n.id == _node.id;
+ });
+ if (hasNodes.length == 0) {
+ if (_self.currentNode != null) {
+ if (_node.id != _self.currentNode.id) {
+ var node = _self.newNode(_node);
+ _self.nodes.push(node);
+ _self.scene.add(node);
+ newNodes.push(node);
+ } else {
+ _self.currentNode.id = _node.id;
+ }
+ } else {
+ var node = _self.newNode(_node);
+ _self.nodes.push(node);
+ _self.scene.add(node);
+ newNodes.push(node);
+ }
+ }
+ });
+ var _nodes_ = _self.nodes;
+ (_links || []).forEach(function (_link) {
+ var hasLinks = _self.links.filter(function (l) {
+ return (
+ l.id == _link.id ||
+ (l.source.id == _link.source && l.target.id == _link.target)
+ );
+ });
+ if (hasLinks.length == 0) {
+ var sourceNode = _nodes_.filter(function (_node) {
+ return _node.id == _link.source;
+ })[0];
+ var targetNode = _nodes_.filter(function (_node) {
+ return _node.id == _link.target;
+ })[0];
+ if (sourceNode != null && targetNode != null) {
+ var link = _self.newEdge(sourceNode, targetNode);
+ link.id = _link.id || "";
+ link.type = _link.type || "default";
+ link.label = _link.label || "";
+ link.showlabel = _link.showlabel || _self.config.link.label.show;
+ link.lineWidth =
+ Number(_link.lineWidth) || _self.config.link.lineWidth;
+ link.weight = Number(_link.weight) || 1;
+ link.lineType = _link.lineType || _self.config.link.lineType;
+ link.lineDash = _link.lineDash || _self.config.link.lineDash;
+ link.strokeColor = _link.color || _self.config.link.color;
+ link.font = _link.font || _self.config.link.label.font;
+ link.fontColor = _link.fontColor || _self.config.link.label.color;
+ link.properties = _link.properties || {};
+ _self.links.push(link);
+ _self.scene.add(link);
+ newLinks.push(link);
+ }
+ }
+ });
+ var unResetNodes = _self.nodes.filter(function (n) {
+ return !n.hasOwnProperty("charge");
+ });
+ unResetNodes.forEach(function (n) {
+ newNodes.push(n);
+ });
+ if (_self.currentNode != null) {
+ newNodes.push(_self.currentNode);
+ }
+ if (newNodes.length > 1) {
+ if (_self.currentNode != null) {
+ (_self.currentNode.inLinks || []).forEach(function (l) {
+ var isNewNode = newNodes.filter(function (n) {
+ return n == l.source;
+ });
+ if (isNewNode == null || isNewNode.length == 0) {
+ l.source.fixed = true;
+ }
+ });
+ _self.currentNode.fixed = true;
+ }
+ _self.collideNodes(_self.nodes);
+ var centerX = (_self.currentNode || { x: 100 }).x || 100;
+ var centerY = (_self.currentNode || { y: 100 }).y || 100;
+ newNodes.forEach((tnode) => {
+ var targetX = tnode.x,
+ targetY = tnode.y;
+ (tnode.x = centerX), (tnode.y = centerY);
+ _self.animate({
+ targets: tnode,
+ x: targetX,
+ y: targetY,
+ duration: 500,
+ easing: "spring",
+ });
+ });
+ }
+ };
+ VisualGraph.prototype.incremaNodesCodinate = function (nodes) {
+ var radius = computeRadius(nodes);
+ var centerNode = this.currentNode || { x: 100, y: 100 };
+ var angle = this.computeParentAngle(centerNode);
+ var x1 = centerNode.x + radius * Math.cos(angle);
+ var y1 = centerNode.y + radius * Math.sin(angle);
+ centerNode.x = x1;
+ centerNode.y = y1;
+ var nodeCount = nodes.length;
+ var xyArr = getXY(centerNode, nodeCount, radius);
+ nodes.forEach((n, i) => {
+ n.x = xyArr[i].x;
+ n.y = xyArr[i].y;
+ });
+ function computeRadius(_nodes) {
+ var nodeRadius = 20;
+ var area = 2 * Math.PI * nodeRadius * nodeRadius * _nodes.length;
+ var radius = Math.round(Math.sqrt(area, 3));
+ return radius;
+ }
+ function getXYA(centerNode, nodeCount, raduis) {
+ var aop = 360.0 / nodeCount;
+ var arr = [];
+ for (var i = 0; i < nodeCount; i++) {
+ var r1 = raduis;
+ if (nodeCount > 10) {
+ r1 = i % 2 == 0 ? raduis + 35 : raduis - 35;
+ }
+ var ao = i * aop;
+ var o1 = {};
+ o1.x = centerNode.x + r1 * Math.cos((ao * Math.PI) / 360);
+ o1.y = centerNode.y + r1 * Math.sin((ao * Math.PI) / 360);
+ arr[i] = o1;
+ }
+ return arr;
+ }
+ function getXY(centerNode, nodeCount, raduis) {
+ if (nodeCount <= 30) {
+ return getXYA(centerNode, nodeCount, raduis);
+ }
+ var arr = [];
+ for (var i = 0; i < nodeCount; i++) {
+ var phi = Math.acos(-1 + (2 * i) / nodeCount);
+ var theta = Math.sqrt(nodeCount * Math.PI) * phi;
+ var sinPhiRadius = Math.sin(phi) * radius;
+ var o1 = {};
+ o1.x = centerNode.x + sinPhiRadius * Math.sin(theta);
+ o1.y = centerNode.y + Math.cos(phi) * radius;
+ arr[i] = o1;
+ }
+ return arr;
+ }
+ };
+ VisualGraph.prototype.collideNodes = function (nodes) {
+ var self = this;
+ var q = self.quadtree(nodes);
+ let num = 1;
+ while (num++ <= 20) {
+ nodes.forEach(function (_node) {
+ q.visit(collide(_node));
+ });
+ }
+ function collide(node) {
+ var nr = node.radius * node.scaleX * 2,
+ nx1 = node.x - nr,
+ nx2 = node.x + nr,
+ ny1 = node.y - nr,
+ ny2 = node.y + nr;
+ return function (quad, x1, y1, x2, y2) {
+ if (quad.point && quad.point !== node) {
+ var x = node.x - quad.point.x,
+ y = node.y - quad.point.y,
+ l = Math.sqrt(x * x + y * y),
+ r = nr + quad.point.radius;
+ if (l < r) {
+ l = ((l - r) / l) * 0.5;
+ node.x -= x *= l;
+ node.y -= y *= l;
+ quad.point.x += x;
+ quad.point.y += y;
+ }
+ }
+ return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
+ };
+ }
+ };
+ VisualGraph.prototype.quadtree = function (points) {
+ var p,
+ i = -1,
+ n = points.length;
+ if (n && isNaN(points[0].x)) {
+ points = points.map(function (p) {
+ return { x: p[0], y: p[1] };
+ });
+ }
+ var x1 = (y1 = Infinity);
+ var x2 = (y2 = -Infinity);
+ while (++i < n) {
+ p = points[i];
+ if (p.x < x1) {
+ x1 = p.x;
+ }
+ if (p.y < y1) {
+ y1 = p.y;
+ }
+ if (p.x > x2) {
+ x2 = p.x;
+ }
+ if (p.y > y2) {
+ y2 = p.y;
+ }
+ }
+ var dx = x2 - x1,
+ dy = y2 - y1;
+ if (dx > dy) {
+ y2 = y1 + dx;
+ } else {
+ x2 = x1 + dy;
+ }
+ function insert(n, p, x1, y1, x2, y2) {
+ if (isNaN(p.x) || isNaN(p.y)) {
+ return;
+ }
+ if (n.leaf) {
+ var v = n.point;
+ if (v) {
+ if (Math.abs(v.x - p.x) + Math.abs(v.y - p.y) < 0.01) {
+ insertChild(n, p, x1, y1, x2, y2);
+ } else {
+ n.point = null;
+ insertChild(n, v, x1, y1, x2, y2);
+ insertChild(n, p, x1, y1, x2, y2);
+ }
+ } else {
+ n.point = p;
+ }
+ } else {
+ insertChild(n, p, x1, y1, x2, y2);
+ }
+ }
+ function insertChild(n, p, x1, y1, x2, y2) {
+ var sx = (x1 + x2) * 0.5,
+ sy = (y1 + y2) * 0.5,
+ right = p.x >= sx,
+ bottom = p.y >= sy,
+ i = (bottom << 1) + right;
+ n.leaf = false;
+ n = n.nodes[i] || (n.nodes[i] = { leaf: true, nodes: [], point: null });
+ if (right) {
+ x1 = sx;
+ } else {
+ x2 = sx;
+ }
+ if (bottom) {
+ y1 = sy;
+ } else {
+ y2 = sy;
+ }
+ insert(n, p, x1, y1, x2, y2);
+ }
+ function quadtreeVisit(f, node, x1, y1, x2, y2) {
+ if (!f(node, x1, y1, x2, y2)) {
+ var sx = (x1 + x2) * 0.5,
+ sy = (y1 + y2) * 0.5,
+ children = node.nodes;
+ if (children[0]) {
+ quadtreeVisit(f, children[0], x1, y1, sx, sy);
+ }
+ if (children[1]) {
+ quadtreeVisit(f, children[1], sx, y1, x2, sy);
+ }
+ if (children[2]) {
+ quadtreeVisit(f, children[2], x1, sy, sx, y2);
+ }
+ if (children[3]) {
+ quadtreeVisit(f, children[3], sx, sy, x2, y2);
+ }
+ }
+ }
+ var root = { leaf: true, nodes: [], point: null };
+ root.add = function (p) {
+ insert(root, p, x1, y1, x2, y2);
+ };
+ root.visit = function (f) {
+ quadtreeVisit(f, root, x1, y1, x2, y2);
+ };
+ points.forEach(root.add);
+ return root;
+ };
+ VisualGraph.prototype.stopRunningLayout = function (layzeTime) {
+ var self = this;
+ setTimeout(function () {
+ cancelAnimationFrame(self.forceOptions.loopName);
+ self.forceOptions.loopName = null;
+ self.forceOptions.alpha = 0;
+ }, layzeTime);
+ };
+ VisualGraph.prototype.loopRunLayout = function (callback) {
+ var _self = this;
+ if (typeof callback == "function") {
+ cancelAnimationFrame(_self.forceOptions.loopName);
+ _self.forceOptions.loopName = null;
+ function loop() {
+ cancelAnimationFrame(_self.forceOptions.loopName);
+ callback();
+ _self.refresh();
+ _self.forceOptions.loopName = requestAnimationFrame(loop);
+ }
+ _self.forceOptions.loopName = requestAnimationFrame(loop);
+ }
+ };
+ VisualGraph.prototype.runLayoutEngin = function (nodes, links, alpha) {
+ var _self = this;
+ if (nodes.length == 0) {
+ return;
+ }
+ _self.forceOptions.alpha = alpha || 0.5;
+ _self.loopRunLayout(tick);
+ function tick() {
+ if ((_self.forceOptions.alpha *= 0.99) < 0.001) {
+ _self.stopRunningLayout(10);
+ _self.forceOptions.alpha = 0;
+ return;
+ }
+ var q, i, o, s, t, l, k, x, y;
+ links.forEach(function (link, i) {
+ s = link.source;
+ t = link.target;
+ x = t.x - s.x;
+ y = t.y - s.y;
+ if ((l = x * x + y * y)) {
+ l =
+ (_self.forceOptions.alpha *
+ link.strength *
+ ((l = Math.sqrt(l)) - link.distance)) /
+ l;
+ x *= l;
+ y *= l;
+ t.x -= x * (k = s.weight / (t.weight + s.weight));
+ t.y -= y * k;
+ s.x += x * (k = 1 - k);
+ s.y += y * k;
+ }
+ });
+ var n = nodes.length;
+ if ((k = _self.forceOptions.alpha * _self.forceOptions.gravity)) {
+ x = _self.forceOptions.size[0] / 2;
+ y = _self.forceOptions.size[1] / 2;
+ i = -1;
+ if (k) {
+ while (++i < n) {
+ o = nodes[i];
+ o.x += (x - o.x) * k;
+ o.y += (y - o.y) * k;
+ }
+ }
+ }
+ if (_self.forceOptions.charge) {
+ forceAccumulate((q = _self.quadtree(nodes)), _self.forceOptions.alpha);
+ i = -1;
+ while (++i < n) {
+ if (!(o = nodes[i]).fixed) {
+ q.visit(repulse(o));
+ }
+ }
+ }
+ i = -1;
+ while (++i < n) {
+ o = nodes[i];
+ if (o.fixed) {
+ if (!o.isDragging) {
+ o.x = o.px;
+ o.y = o.py;
+ } else {
+ o.px = o.x;
+ o.py = o.y;
+ }
+ } else {
+ o.x -= (o.px - (o.px = o.x)) * _self.forceOptions.friction;
+ o.y -= (o.py - (o.py = o.y)) * _self.forceOptions.friction;
+ if (_self.forceOptions.noverlap == true) {
+ q.visit(collide(o));
+ }
+ }
+ }
+ function repulse(node) {
+ return function (quad, x1, y1, x2, y2) {
+ if (quad.point !== node) {
+ var dx = quad.cx - node.x,
+ dy = quad.cy - node.y,
+ dn = 1 / Math.sqrt(dx * dx + dy * dy);
+ if ((x2 - x1) * dn < _self.forceOptions.theta) {
+ var k = quad.charge * dn * dn;
+ node.px -= dx * k;
+ node.py -= dy * k;
+ return true;
+ }
+ if (quad.point && isFinite(dn)) {
+ var k = quad.pointCharge * dn * dn;
+ node.px -= dx * k;
+ node.py -= dy * k;
+ }
+ }
+ return !quad.charge;
+ };
+ }
+ function collide(node) {
+ var nodeR = node.radius * node.scaleX * 2,
+ nx1 = node.x - nodeR,
+ nx2 = node.x + nodeR,
+ ny1 = node.y - nodeR,
+ ny2 = node.y + nodeR;
+ return function (quad, x1, y1, x2, y2) {
+ if (quad.point && quad.point !== node) {
+ var x = node.x - quad.point.x,
+ y = node.y - quad.point.y,
+ l = Math.sqrt(x * x + y * y),
+ r = nodeR + quad.point.radius;
+ if (l < r) {
+ l = ((l - r) / l) * 0.5;
+ node.x -= x *= l;
+ node.y -= y *= l;
+ quad.point.x += x;
+ quad.point.y += y;
+ }
+ }
+ return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
+ };
+ }
+ }
+ function forceAccumulate(quad, alpha) {
+ var cx = 0,
+ cy = 0;
+ quad.charge = 0;
+ if (!quad.leaf) {
+ var nodes = quad.nodes,
+ n = nodes.length,
+ i = -1,
+ c;
+ while (++i < n) {
+ c = nodes[i];
+ if (c == null) {
+ continue;
+ }
+ forceAccumulate(c, alpha);
+ quad.charge += c.charge;
+ cx += c.charge * c.cx;
+ cy += c.charge * c.cy;
+ }
+ }
+ if (quad.point) {
+ if (!quad.leaf) {
+ quad.point.x += Math.random() - 0.5;
+ quad.point.y += Math.random() - 0.5;
+ }
+ var k = _self.forceOptions.alpha * quad.point.charge;
+ quad.charge += quad.pointCharge = k;
+ cx += k * quad.point.x;
+ cy += k * quad.point.y;
+ }
+ quad.cx = cx / quad.charge;
+ quad.cy = cy / quad.charge;
+ }
+ };
+ VisualGraph.prototype.getAllSelectedNodes = function () {
+ var nodes = this.nodes.filter(function (n) {
+ return n.selected == true;
+ });
+ return nodes;
+ };
+ VisualGraph.prototype.findNodeByAttr = function (attr, value) {
+ var nodes = this.nodes.filter(function (n) {
+ return n[attr] == value;
+ });
+ if (nodes.length > 0) {
+ var node = nodes[0];
+ return node;
+ }
+ return null;
+ };
+ VisualGraph.prototype.findNodeById = function (nodeId) {
+ var nodes = this.nodes.filter(function (n) {
+ return n.id == nodeId;
+ });
+ if (nodes.length > 0) {
+ var node = nodes[0];
+ node.selected = true;
+ node.visible = true;
+ this.scene.addToSelected(node);
+ this.focusTargetEle(node);
+ return node;
+ }
+ return null;
+ };
+ VisualGraph.prototype.updateNodeLabel = function (nodeId, nodeName) {
+ var node = this.nodes.filter(function (_node) {
+ return _node.id == nodeId;
+ })[0];
+ if (node) {
+ node.label = nodeName;
+ node.text = nodeName;
+ this.refresh();
+ }
+ };
+ VisualGraph.prototype.switchAnimate = function (flag) {
+ if (!flag) {
+ this.stage.fps = -50;
+ } else {
+ this.stage.fps = 50;
+ }
+ };
+ VisualGraph.prototype.setStaticMode = function (flag) {
+ this.stage.staticMode = flag;
+ };
+ VisualGraph.prototype.setSmoothWheelMode = function (flag) {
+ this.stage.smoothWheelMode = flag;
+ };
+ VisualGraph.prototype.setShowDetailScale = function (scale) {
+ this.stage.showDetailScale = Number(scale) || 0.5;
+ };
+ VisualGraph.prototype.setDragHideLineEffect = function (flag) {
+ this.stage.openDragHideEffect = Boolean(flag);
+ };
+ VisualGraph.prototype.updateThumbnail = function () {
+ this.stage.thumbnail.visible && this.stage.thumbnail.update();
+ };
+ VisualGraph.prototype.randomColor = function () {
+ return (
+ Math.floor(255 * Math.random()) +
+ "," +
+ Math.floor(360 * Math.random()) +
+ "," +
+ Math.floor(255 * Math.random())
+ );
+ };
+ VisualGraph.prototype.buildVisualGraphData = function (_nodes, _links) {
+ var nodeIdMapNode = new Map();
+ _nodes.forEach(function (n) {
+ n.scaleX = 1;
+ n.scaleY = 1;
+ n.radius = n.radius || n.width || 30;
+ n.x = n.x || Math.round(Math.random() * 1000);
+ n.y = n.y || Math.round(Math.random() * 1000);
+ n.cx = n.x;
+ n.cy = n.x;
+ if (n.id == 1) {
+ n.selected = true;
+ } else {
+ n.selected = false;
+ }
+ nodeIdMapNode.set(n.id, n);
+ });
+ var links = [];
+ _links.forEach(function (l) {
+ var sourceNode = nodeIdMapNode.get(l.source),
+ targetNode = nodeIdMapNode.get(l.target);
+ if (sourceNode) {
+ sourceNode.outLinks = sourceNode.outLinks || [];
+ sourceNode.outLinks.push({ source: sourceNode, target: targetNode });
+ }
+ if (targetNode) {
+ targetNode.inLinks = targetNode.inLinks || [];
+ targetNode.inLinks.push({ source: sourceNode, target: targetNode });
+ }
+ links.push({ source: sourceNode, target: targetNode });
+ });
+ var newNodes = [];
+ nodeIdMapNode.forEach(function (value, key) {
+ newNodes.push(value);
+ });
+ return { nodes: newNodes, links: links };
+ };
+ VisualGraph.prototype.algorithm = function () {
+ return DGraph.util;
+ };
+ VisualGraph.prototype.preResetNodeCoords = function (
+ nodes,
+ center = [100, 100],
+ nodeSpace = 80,
+ needScale = true,
+ ) {
+ var newNodes = [].concat(nodes);
+ newNodes.sort((nodeA, nodeB) => {
+ return (
+ (nodeB.inLinks || []).length +
+ (nodeB.outLinks || []).length -
+ ((nodeA.inLinks || []).length + (nodeA.outLinks || []).length)
+ );
+ });
+ var theta = Math.PI * (3 - Math.sqrt(5));
+ var centerX = center[0];
+ var centerY = center[1];
+ var radius = 0,
+ angle = 0;
+ newNodes.forEach((node, i) => {
+ radius = nodeSpace * Math.sqrt((i += 0.5));
+ angle = theta * i;
+ if (i == 0) {
+ node = centerX;
+ node = centerY;
+ node.fixed = true;
+ } else {
+ node.x = centerX + radius * Math.cos(angle);
+ node.y = centerY + radius * Math.sin(angle);
+ }
+ });
+ if (needScale) {
+ this.moveCenter(this.scene.scaleRange[0]);
+ }
+ };
+ VisualGraph.prototype.showLoadProcess = function (
+ loadText = "Loading",
+ percent = 0.1,
+ ) {
+ this.stage.showLoading(loadText, percent);
+ };
+ VisualGraph.prototype.hideLoadProcess = function () {
+ this.stage.hideLoading();
+ };
+ VisualGraph.prototype.getViewCenter = function () {
+ return {
+ x: this.stage.width / 2 - this.scene.translateX,
+ y: this.stage.height / 2 - this.scene.translateY,
+ };
+ };
+ VisualGraph.prototype.genRgbGradientColors = function (
+ num,
+ rbgColorFrom,
+ rgbColorTo,
+ ) {
+ var ctool = new DGraph.ColorUtils();
+ var colors = ctool.genRgbGradientColors(num, rbgColorFrom, rgbColorTo);
+ return colors;
+ };
+ VisualGraph.prototype.setDataDragAble = function (dragable = true) {
+ this.scene.dragable = dragable;
+ };
+ VisualGraph.prototype.animate = function (config) {
+ var self = this;
+ var defaultInstanceSettings = {
+ update: null,
+ begin: null,
+ loopBegin: null,
+ changeBegin: null,
+ change: null,
+ changeComplete: null,
+ loopComplete: null,
+ complete: null,
+ loop: 1,
+ direction: "normal",
+ autoplay: true,
+ timelineOffset: 0,
+ };
+ var defaultTweenSettings = {
+ duration: 1000,
+ delay: 0,
+ endDelay: 0,
+ easing: "easeOutElastic(1,.5)",
+ round: 0,
+ };
+ function minMax(val, min, max) {
+ return Math.min(Math.max(val, min), max);
+ }
+ function applyArguments(func, args) {
+ if (func) {
+ return func.apply(null, args);
+ }
+ return;
+ }
+ var is = {
+ arr: function (a) {
+ return Array.isArray(a);
+ },
+ obj: function (a) {
+ return Object.prototype.toString.call(a).indexOf("Object") > -1;
+ },
+ str: function (a) {
+ return typeof a === "string";
+ },
+ fnc: function (a) {
+ return typeof a === "function";
+ },
+ und: function (a) {
+ return typeof a === "undefined";
+ },
+ key: function (a) {
+ return (
+ !defaultInstanceSettings.hasOwnProperty(a) &&
+ !defaultTweenSettings.hasOwnProperty(a) &&
+ a !== "targets" &&
+ a !== "keyframes"
+ );
+ },
+ };
+ function parseEasingParameters(string) {
+ var match = /\(([^)]+)\)/.exec(string);
+ return match
+ ? match[1].split(",").map(function (p) {
+ return parseFloat(p);
+ })
+ : [];
+ }
+ var cache = { springs: {} };
+ function spring(string, duration) {
+ var params = parseEasingParameters(string);
+ var mass = minMax(is.und(params[0]) ? 1 : params[0], 0.1, 100);
+ var stiffness = minMax(is.und(params[1]) ? 100 : params[1], 0.1, 100);
+ var damping = minMax(is.und(params[2]) ? 10 : params[2], 0.1, 100);
+ var velocity = minMax(is.und(params[3]) ? 0 : params[3], 0.1, 100);
+ var w0 = Math.sqrt(stiffness / mass);
+ var zeta = damping / (2 * Math.sqrt(stiffness * mass));
+ var wd = zeta < 1 ? w0 * Math.sqrt(1 - zeta * zeta) : 0;
+ var a = 1;
+ var b = zeta < 1 ? (zeta * w0 + -velocity) / wd : -velocity + w0;
+ function solver(t) {
+ var progress = duration ? (duration * t) / 1000 : t;
+ if (zeta < 1) {
+ progress =
+ Math.exp(-progress * zeta * w0) *
+ (a * Math.cos(wd * progress) + b * Math.sin(wd * progress));
+ } else {
+ progress = (a + b * progress) * Math.exp(-progress * w0);
+ }
+ if (t === 0 || t === 1) {
+ return t;
+ }
+ return 1 - progress;
+ }
+ function getDuration() {
+ var cached = cache.springs[string];
+ if (cached) {
+ return cached;
+ }
+ var frame = 1 / 6;
+ var elapsed = 0;
+ var rest = 0;
+ while (true) {
+ elapsed += frame;
+ if (solver(elapsed) === 1) {
+ rest++;
+ if (rest >= 16) {
+ break;
+ }
+ } else {
+ rest = 0;
+ }
+ }
+ var duration = elapsed * frame * 1000;
+ cache.springs[string] = duration;
+ return duration;
+ }
+ return duration ? solver : getDuration;
+ }
+ function steps(steps) {
+ if (steps === void 0) steps = 10;
+ return function (t) {
+ return Math.round(t * steps) * (1 / steps);
+ };
+ }
+ var penner = (function () {
+ var eases = {
+ linear: function () {
+ return function (t) {
+ return t;
+ };
+ },
+ };
+ var functionEasings = {
+ Sine: function () {
+ return function (t) {
+ return 1 - Math.cos((t * Math.PI) / 2);
+ };
+ },
+ Circ: function () {
+ return function (t) {
+ return 1 - Math.sqrt(1 - t * t);
+ };
+ },
+ Back: function () {
+ return function (t) {
+ return t * t * (3 * t - 2);
+ };
+ },
+ Bounce: function () {
+ return function (t) {
+ var pow2,
+ b = 4;
+ while (t < ((pow2 = Math.pow(2, --b)) - 1) / 11) {}
+ return (
+ 1 / Math.pow(4, 3 - b) -
+ 7.5625 * Math.pow((pow2 * 3 - 2) / 22 - t, 2)
+ );
+ };
+ },
+ Elastic: function (amplitude, period) {
+ if (amplitude === void 0) amplitude = 1;
+ if (period === void 0) period = 0.5;
+ var a = minMax(amplitude, 1, 10);
+ var p = minMax(period, 0.1, 2);
+ return function (t) {
+ return t === 0 || t === 1
+ ? t
+ : -a *
+ Math.pow(2, 10 * (t - 1)) *
+ Math.sin(
+ ((t - 1 - (p / (Math.PI * 2)) * Math.asin(1 / a)) *
+ (Math.PI * 2)) /
+ p,
+ );
+ };
+ },
+ };
+ var baseEasings = ["Quad", "Cubic", "Quart", "Quint", "Expo"];
+ baseEasings.forEach(function (name, i) {
+ functionEasings[name] = function () {
+ return function (t) {
+ return Math.pow(t, i + 2);
+ };
+ };
+ });
+ Object.keys(functionEasings).forEach(function (name) {
+ var easeIn = functionEasings[name];
+ eases["easeIn" + name] = easeIn;
+ eases["easeOut" + name] = function (a, b) {
+ return function (t) {
+ return 1 - easeIn(a, b)(1 - t);
+ };
+ };
+ eases["easeInOut" + name] = function (a, b) {
+ return function (t) {
+ return t < 0.5
+ ? easeIn(a, b)(t * 2) / 2
+ : 1 - easeIn(a, b)(t * -2 + 2) / 2;
+ };
+ };
+ });
+ return eases;
+ })();
+ function parseEasings(easing, duration) {
+ if (is.fnc(easing)) {
+ return easing;
+ }
+ var name = easing.split("(")[0];
+ var ease = penner[name];
+ var args = parseEasingParameters(easing);
+ switch (name) {
+ case "spring":
+ return spring(easing, duration);
+ case "steps":
+ return applyArguments(steps, args);
+ default:
+ return applyArguments(ease, args);
+ }
+ }
+ function filterArray(arr, callback) {
+ var len = arr.length;
+ var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
+ var result = [];
+ for (var i = 0; i < len; i++) {
+ if (i in arr) {
+ var val = arr[i];
+ if (callback.call(thisArg, val, i, arr)) {
+ result.push(val);
+ }
+ }
+ }
+ return result;
+ }
+ function flattenArray(arr) {
+ return arr.reduce(function (a, b) {
+ return a.concat(is.arr(b) ? flattenArray(b) : b);
+ }, []);
+ }
+ function toArray(o) {
+ if (is.arr(o)) {
+ return o;
+ }
+ if (o instanceof NodeList || o instanceof HTMLCollection) {
+ return [].slice.call(o);
+ }
+ return [o];
+ }
+ function cloneObject(o) {
+ var clone = {};
+ for (var p in o) {
+ clone[p] = o[p];
+ }
+ return clone;
+ }
+ function replaceObjectProps(o1, o2) {
+ var o = cloneObject(o1);
+ for (var p in o1) {
+ o[p] = o2.hasOwnProperty(p) ? o2[p] : o1[p];
+ }
+ return o;
+ }
+ function mergeObjects(o1, o2) {
+ var o = cloneObject(o1);
+ for (var p in o2) {
+ o[p] = is.und(o1[p]) ? o2[p] : o1[p];
+ }
+ return o;
+ }
+ function getUnit(val) {
+ var split =
+ /[+-]?\d*\.?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?(%|px|pt|em|rem|in|cm|mm|ex|ch|pc|vw|vh|vmin|vmax|deg|rad|turn)?$/.exec(
+ val,
+ );
+ if (split) {
+ return split[1];
+ }
+ }
+ function getFunctionValue(val, animatable) {
+ if (!is.fnc(val)) {
+ return val;
+ }
+ return val(animatable.target, animatable.id, animatable.total);
+ }
+ function getOriginalTargetValue(target, propName, unit, animatable) {
+ return target[propName] || 0;
+ }
+ function getRelativeValue(to, from) {
+ var operator = /^(\*=|\+=|-=)/.exec(to);
+ if (!operator) {
+ return to;
+ }
+ var u = getUnit(to) || 0;
+ var x = parseFloat(from);
+ var y = parseFloat(to.replace(operator[0], ""));
+ switch (operator[0][0]) {
+ case "+":
+ return x + y + u;
+ case "-":
+ return x - y + u;
+ case "*":
+ return x * y + u;
+ }
+ }
+ function validateValue(val, unit) {
+ if (/\s/g.test(val)) {
+ return val;
+ }
+ var originalUnit = getUnit(val);
+ var unitLess = originalUnit
+ ? val.substr(0, val.length - originalUnit.length)
+ : val;
+ if (unit) {
+ return unitLess + unit;
+ }
+ return unitLess;
+ }
+ function decomposeValue(val, unit) {
+ var rgx = /[+-]?\d*\.?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/g;
+ var value = validateValue(val, unit) + "";
+ return {
+ original: value,
+ numbers: value.match(rgx) ? value.match(rgx).map(Number) : [0],
+ strings: is.str(val) || unit ? value.split(rgx) : [],
+ };
+ }
+ function parseTargets(targets) {
+ var targetsArray = targets
+ ? flattenArray(
+ is.arr(targets) ? targets.map(toArray) : toArray(targets),
+ )
+ : [];
+ return filterArray(targetsArray, function (item, pos, self) {
+ return self.indexOf(item) === pos;
+ });
+ }
+ function getAnimatables(targets) {
+ var parsed = parseTargets(targets);
+ return parsed.map(function (t, i) {
+ return { target: t, id: i, total: parsed.length };
+ });
+ }
+ function normalizePropertyTweens(prop, tweenSettings) {
+ var settings = cloneObject(tweenSettings);
+ if (/^spring/.test(settings.easing)) {
+ settings.duration = spring(settings.easing);
+ }
+ if (is.arr(prop)) {
+ var l = prop.length;
+ var isFromTo = l === 2 && !is.obj(prop[0]);
+ if (!isFromTo) {
+ if (!is.fnc(tweenSettings.duration)) {
+ settings.duration = tweenSettings.duration / l;
+ }
+ } else {
+ prop = { value: prop };
+ }
+ }
+ var propArray = is.arr(prop) ? prop : [prop];
+ return propArray
+ .map(function (v, i) {
+ var obj = is.obj(v) ? v : { value: v };
+ if (is.und(obj.delay)) {
+ obj.delay = !i ? tweenSettings.delay : 0;
+ }
+ if (is.und(obj.endDelay)) {
+ obj.endDelay =
+ i === propArray.length - 1 ? tweenSettings.endDelay : 0;
+ }
+ return obj;
+ })
+ .map(function (k) {
+ return mergeObjects(k, settings);
+ });
+ }
+ function flattenKeyframes(keyframes) {
+ var propertyNames = filterArray(
+ flattenArray(
+ keyframes.map(function (key) {
+ return Object.keys(key);
+ }),
+ ),
+ function (p) {
+ return is.key(p);
+ },
+ ).reduce(function (a, b) {
+ if (a.indexOf(b) < 0) {
+ a.push(b);
+ }
+ return a;
+ }, []);
+ var properties = {};
+ var loop = function (i) {
+ var propName = propertyNames[i];
+ properties[propName] = keyframes.map(function (key) {
+ var newKey = {};
+ for (var p in key) {
+ if (is.key(p)) {
+ if (p == propName) {
+ newKey.value = key[p];
+ }
+ } else {
+ newKey[p] = key[p];
+ }
+ }
+ return newKey;
+ });
+ };
+ for (var i = 0; i < propertyNames.length; i++) loop(i);
+ }
+ function getProperties(tweenSettings, params) {
+ var properties = [];
+ var keyframes = params.keyframes;
+ if (keyframes) {
+ params = mergeObjects(flattenKeyframes(keyframes), params);
+ }
+ for (var p in params) {
+ if (is.key(p)) {
+ properties.push({
+ name: p,
+ tweens: normalizePropertyTweens(params[p], tweenSettings),
+ });
+ }
+ }
+ return properties;
+ }
+ function normalizeTweenValues(tween, animatable) {
+ var t = {};
+ for (var p in tween) {
+ var value = getFunctionValue(tween[p], animatable);
+ if (is.arr(value)) {
+ value = value.map(function (v) {
+ return getFunctionValue(v, animatable);
+ });
+ if (value.length === 1) {
+ value = value[0];
+ }
+ }
+ t[p] = value;
+ }
+ t.duration = parseFloat(t.duration);
+ t.delay = parseFloat(t.delay);
+ return t;
+ }
+ function normalizeTweens(prop, animatable) {
+ var previousTween;
+ return prop.tweens.map(function (t) {
+ var tween = normalizeTweenValues(t, animatable);
+ var tweenValue = tween.value;
+ var to = is.arr(tweenValue) ? tweenValue[1] : tweenValue;
+ var toUnit = getUnit(to);
+ var originalValue = getOriginalTargetValue(
+ animatable.target,
+ prop.name,
+ toUnit,
+ animatable,
+ );
+ var previousValue = previousTween
+ ? previousTween.to.original
+ : originalValue;
+ var from = is.arr(tweenValue) ? tweenValue[0] : previousValue;
+ var fromUnit = getUnit(from) || getUnit(originalValue);
+ var unit = toUnit || fromUnit;
+ if (is.und(to)) {
+ to = previousValue;
+ }
+ tween.from = decomposeValue(from, unit);
+ tween.to = decomposeValue(getRelativeValue(to, from), unit);
+ tween.start = previousTween ? previousTween.end : 0;
+ tween.end = tween.start + tween.delay + tween.duration + tween.endDelay;
+ tween.easing = parseEasings(tween.easing, tween.duration);
+ previousTween = tween;
+ return tween;
+ });
+ }
+ var setProgressValue = {
+ object: function (t, p, v) {
+ return (t[p] = v);
+ },
+ };
+ function setTargetsValue(targets, properties) {
+ var animatables = getAnimatables(targets);
+ animatables.forEach(function (animatable) {
+ for (var property in properties) {
+ var value = getFunctionValue(properties[property], animatable);
+ var target = animatable.target;
+ var valueUnit = getUnit(value);
+ var originalValue = getOriginalTargetValue(
+ target,
+ property,
+ valueUnit,
+ animatable,
+ );
+ var unit = valueUnit || getUnit(originalValue);
+ var to = getRelativeValue(validateValue(value, unit), originalValue);
+ var animType = "object";
+ setProgressValue[animType](
+ target,
+ property,
+ to,
+ animatable.transforms,
+ true,
+ );
+ }
+ });
+ }
+ function createAnimation(animatable, prop) {
+ var tweens = normalizeTweens(prop, animatable);
+ var lastTween = tweens[tweens.length - 1];
+ return {
+ type: "object",
+ property: prop.name,
+ animatable: animatable,
+ tweens: tweens,
+ duration: lastTween.end,
+ delay: tweens[0].delay,
+ endDelay: lastTween.endDelay,
+ };
+ }
+ function getAnimations(animatables, properties) {
+ return filterArray(
+ flattenArray(
+ animatables.map(function (animatable) {
+ return properties.map(function (prop) {
+ return createAnimation(animatable, prop);
+ });
+ }),
+ ),
+ function (a) {
+ return !is.und(a);
+ },
+ );
+ }
+ function getInstanceTimings(animations, tweenSettings) {
+ var animLength = animations.length;
+ var getTlOffset = function (anim) {
+ return anim.timelineOffset ? anim.timelineOffset : 0;
+ };
+ var timings = {};
+ timings.duration = animLength
+ ? Math.max.apply(
+ Math,
+ animations.map(function (anim) {
+ return getTlOffset(anim) + anim.duration;
+ }),
+ )
+ : tweenSettings.duration;
+ timings.delay = animLength
+ ? Math.min.apply(
+ Math,
+ animations.map(function (anim) {
+ return getTlOffset(anim) + anim.delay;
+ }),
+ )
+ : tweenSettings.delay;
+ timings.endDelay = animLength
+ ? timings.duration -
+ Math.max.apply(
+ Math,
+ animations.map(function (anim) {
+ return getTlOffset(anim) + anim.duration - anim.endDelay;
+ }),
+ )
+ : tweenSettings.endDelay;
+ return timings;
+ }
+ var instanceID = 0;
+ function createNewInstance(params) {
+ var instanceSettings = replaceObjectProps(
+ defaultInstanceSettings,
+ params,
+ );
+ var tweenSettings = replaceObjectProps(defaultTweenSettings, params);
+ var properties = getProperties(tweenSettings, params);
+ var animatables = getAnimatables(params.targets);
+ var animations = getAnimations(animatables, properties);
+ var timings = getInstanceTimings(animations, tweenSettings);
+ var id = instanceID;
+ instanceID++;
+ return mergeObjects(instanceSettings, {
+ id: id,
+ children: [],
+ animatables: animatables,
+ animations: animations,
+ duration: timings.duration,
+ delay: timings.delay,
+ endDelay: timings.endDelay,
+ });
+ }
+ var activeInstances = [];
+ var pausedInstances = [];
+ var raf;
+ var engine = (function () {
+ function play() {
+ raf = requestAnimationFrame(step);
+ }
+ function step(t) {
+ var activeInstancesLength = activeInstances.length;
+ if (activeInstancesLength) {
+ var i = 0;
+ while (i < activeInstancesLength) {
+ var activeInstance = activeInstances[i];
+ if (!activeInstance.paused) {
+ activeInstance.tick(t);
+ } else {
+ var instanceIndex = activeInstances.indexOf(activeInstance);
+ if (instanceIndex > -1) {
+ activeInstances.splice(instanceIndex, 1);
+ activeInstancesLength = activeInstances.length;
+ }
+ }
+ i++;
+ }
+ play();
+ } else {
+ raf = cancelAnimationFrame(raf);
+ }
+ }
+ return play;
+ })();
+ function anime(params) {
+ if (params === void 0) {
+ params = {};
+ }
+ var startTime = 0,
+ lastTime = 0,
+ now = 0;
+ var children,
+ childrenLength = 0;
+ var resolve = null;
+ var speed = 1;
+ function makePromise(instance) {
+ var promise =
+ window.Promise &&
+ new Promise(function (_resolve) {
+ return (resolve = _resolve);
+ });
+ instance.finished = promise;
+ return promise;
+ }
+ var instance = createNewInstance(params);
+ var promise = makePromise(instance);
+ function toggleInstanceDirection() {
+ var direction = instance.direction;
+ if (direction !== "alternate") {
+ instance.direction = direction !== "normal" ? "normal" : "reverse";
+ }
+ instance.reversed = !instance.reversed;
+ children.forEach(function (child) {
+ return (child.reversed = instance.reversed);
+ });
+ }
+ function adjustTime(time) {
+ return instance.reversed ? instance.duration - time : time;
+ }
+ function resetTime() {
+ startTime = 0;
+ lastTime = adjustTime(instance.currentTime) * (1 / speed);
+ }
+ function seekChild(time, child) {
+ if (child) {
+ child.seek(time - child.timelineOffset);
+ }
+ }
+ function syncInstanceChildren(time) {
+ if (!instance.reversePlayback) {
+ for (var i = 0; i < childrenLength; i++) {
+ seekChild(time, children[i]);
+ }
+ } else {
+ for (var i$1 = childrenLength; i$1--; ) {
+ seekChild(time, children[i$1]);
+ }
+ }
+ }
+ function setAnimationsProgress(insTime) {
+ var i = 0;
+ var animations = instance.animations;
+ var animationsLength = animations.length;
+ while (i < animationsLength) {
+ var anim = animations[i];
+ var animatable = anim.animatable;
+ var tweens = anim.tweens;
+ var tweenLength = tweens.length - 1;
+ var tween = tweens[tweenLength];
+ if (tweenLength) {
+ tween =
+ filterArray(tweens, function (t) {
+ return insTime < t.end;
+ })[0] || tween;
+ }
+ var elapsed =
+ minMax(insTime - tween.start - tween.delay, 0, tween.duration) /
+ tween.duration;
+ var eased = isNaN(elapsed) ? 1 : tween.easing(elapsed);
+ var strings = tween.to.strings;
+ var round = tween.round;
+ var numbers = [];
+ var toNumbersLength = tween.to.numbers.length;
+ var progress = void 0;
+ for (var n = 0; n < toNumbersLength; n++) {
+ var value = void 0;
+ var toNumber = tween.to.numbers[n];
+ var fromNumber = tween.from.numbers[n] || 0;
+ value = fromNumber + eased * (toNumber - fromNumber);
+ numbers.push(value);
+ }
+ var stringsLength = strings.length;
+ if (!stringsLength) {
+ progress = numbers[0];
+ } else {
+ progress = strings[0];
+ for (var s = 0; s < stringsLength; s++) {
+ var a = strings[s];
+ var b = strings[s + 1];
+ var n$1 = numbers[s];
+ if (!isNaN(n$1)) {
+ if (!b) {
+ progress += n$1 + " ";
+ } else {
+ progress += n$1 + b;
+ }
+ }
+ }
+ }
+ setProgressValue[anim.type](
+ animatable.target,
+ anim.property,
+ progress,
+ animatable.transforms,
+ );
+ anim.currentValue = progress;
+ i++;
+ }
+ }
+ function setCallback(cb) {
+ if (instance[cb] && !instance.passThrough) {
+ instance[cb](instance);
+ }
+ if (cb == "update") {
+ self.refresh();
+ }
+ }
+ function countIteration() {
+ if (instance.remaining && instance.remaining !== true) {
+ instance.remaining--;
+ }
+ }
+ function setInstanceProgress(engineTime) {
+ var insDuration = instance.duration;
+ var insDelay = instance.delay;
+ var insEndDelay = insDuration - instance.endDelay;
+ var insTime = adjustTime(engineTime);
+ instance.progress = minMax((insTime / insDuration) * 100, 0, 100);
+ instance.reversePlayback = insTime < instance.currentTime;
+ if (children) {
+ syncInstanceChildren(insTime);
+ }
+ if (!instance.began && instance.currentTime > 0) {
+ instance.began = true;
+ setCallback("begin");
+ }
+ if (!instance.loopBegan && instance.currentTime > 0) {
+ instance.loopBegan = true;
+ setCallback("loopBegin");
+ }
+ if (insTime <= insDelay && instance.currentTime !== 0) {
+ setAnimationsProgress(0);
+ }
+ if (
+ (insTime >= insEndDelay && instance.currentTime !== insDuration) ||
+ !insDuration
+ ) {
+ setAnimationsProgress(insDuration);
+ }
+ if (insTime > insDelay && insTime < insEndDelay) {
+ if (!instance.changeBegan) {
+ instance.changeBegan = true;
+ instance.changeCompleted = false;
+ setCallback("changeBegin");
+ }
+ setCallback("change");
+ setAnimationsProgress(insTime);
+ } else {
+ if (instance.changeBegan) {
+ instance.changeCompleted = true;
+ instance.changeBegan = false;
+ setCallback("changeComplete");
+ }
+ }
+ instance.currentTime = minMax(insTime, 0, insDuration);
+ if (instance.began) {
+ setCallback("update");
+ }
+ if (engineTime >= insDuration) {
+ lastTime = 0;
+ countIteration();
+ if (!instance.remaining) {
+ instance.paused = true;
+ if (!instance.completed) {
+ instance.completed = true;
+ setCallback("loopComplete");
+ setCallback("complete");
+ if (!instance.passThrough && "Promise" in window) {
+ resolve();
+ promise = makePromise(instance);
+ }
+ }
+ } else {
+ startTime = now;
+ setCallback("loopComplete");
+ instance.loopBegan = false;
+ if (instance.direction === "alternate") {
+ toggleInstanceDirection();
+ }
+ }
+ }
+ }
+ instance.reset = function () {
+ var direction = instance.direction;
+ instance.passThrough = false;
+ instance.currentTime = 0;
+ instance.progress = 0;
+ instance.paused = true;
+ instance.began = false;
+ instance.loopBegan = false;
+ instance.changeBegan = false;
+ instance.completed = false;
+ instance.changeCompleted = false;
+ instance.reversePlayback = false;
+ instance.reversed = direction === "reverse";
+ instance.remaining = instance.loop;
+ children = instance.children;
+ childrenLength = children.length;
+ for (var i = childrenLength; i--; ) {
+ instance.children[i].reset();
+ }
+ if (
+ (instance.reversed && instance.loop !== true) ||
+ (direction === "alternate" && instance.loop === 1)
+ ) {
+ instance.remaining++;
+ }
+ setAnimationsProgress(instance.reversed ? instance.duration : 0);
+ };
+ instance.set = function (targets, properties) {
+ setTargetsValue(targets, properties);
+ return instance;
+ };
+ instance.tick = function (t) {
+ now = t;
+ if (!startTime) {
+ startTime = now;
+ }
+ setInstanceProgress((now + (lastTime - startTime)) * speed);
+ };
+ instance.seek = function (time) {
+ setInstanceProgress(adjustTime(time));
+ };
+ instance.pause = function () {
+ instance.paused = true;
+ resetTime();
+ };
+ instance.play = function () {
+ if (!instance.paused) {
+ return;
+ }
+ if (instance.completed) {
+ instance.reset();
+ }
+ instance.paused = false;
+ activeInstances.push(instance);
+ resetTime();
+ if (!raf) {
+ engine();
+ }
+ };
+ instance.reverse = function () {
+ toggleInstanceDirection();
+ resetTime();
+ };
+ instance.restart = function () {
+ instance.reset();
+ instance.play();
+ };
+ instance.reset();
+ if (instance.autoplay) {
+ instance.play();
+ }
+ instance.timeline = function (params) {
+ if (params === void 0) {
+ params = {};
+ }
+ var tl = anime(params);
+ tl.duration = 0;
+ tl.add = function (instanceParams, timelineOffset) {
+ var tlIndex = activeInstances.indexOf(tl);
+ var children = tl.children;
+ if (tlIndex > -1) {
+ activeInstances.splice(tlIndex, 1);
+ }
+ function passThrough(ins) {
+ ins.passThrough = true;
+ }
+ for (var i = 0; i < children.length; i++) {
+ passThrough(children[i]);
+ }
+ var insParams = mergeObjects(
+ instanceParams,
+ replaceObjectProps(defaultTweenSettings, params),
+ );
+ insParams.targets = insParams.targets || params.targets;
+ var tlDuration = tl.duration;
+ insParams.autoplay = false;
+ insParams.direction = tl.direction;
+ insParams.timelineOffset = is.und(timelineOffset)
+ ? tlDuration
+ : getRelativeValue(timelineOffset, tlDuration);
+ passThrough(tl);
+ tl.seek(insParams.timelineOffset);
+ var ins = anime(insParams);
+ passThrough(ins);
+ children.push(ins);
+ var timings = getInstanceTimings(children, params);
+ tl.delay = timings.delay;
+ tl.endDelay = timings.endDelay;
+ tl.duration = timings.duration;
+ tl.seek(0);
+ tl.reset();
+ if (tl.autoplay) {
+ tl.play();
+ }
+ return tl;
+ };
+ return tl;
+ };
+ return instance;
+ }
+ return anime(config);
+ };
+ var VisGraph = VisualGraph;
+ if (typeof module !== "undefined" && typeof exports === "object") {
+ module.exports = VisGraph;
+ } else if (typeof define === "function" && (define.amd || define.cmd)) {
+ define(function () {
+ return VisGraph;
+ });
+ } else {
+ this.VisGraph = VisGraph;
+ }
+}).call(this || (typeof window !== "undefined" ? window : global));
diff --git a/kcui/src/assets/logo.png b/kcui/src/assets/logo.png
new file mode 100644
index 0000000..f3d2503
Binary files /dev/null and b/kcui/src/assets/logo.png differ
diff --git a/kcui/src/components/HelloWorld.vue b/kcui/src/components/HelloWorld.vue
new file mode 100644
index 0000000..879051a
--- /dev/null
+++ b/kcui/src/components/HelloWorld.vue
@@ -0,0 +1,58 @@
+
+
+
{{ msg }}
+
+ For a guide and recipes on how to configure / customize this project,
+ check out the
+ vue-cli documentation.
+
+
Installed CLI Plugins
+
+
Essential Links
+
+
Ecosystem
+
+
+
+
+
+
+
+
diff --git a/kcui/src/main.js b/kcui/src/main.js
new file mode 100644
index 0000000..da99e79
--- /dev/null
+++ b/kcui/src/main.js
@@ -0,0 +1,16 @@
+import Vue from 'vue'
+import App from './App.vue'
+import VueRouter from 'vue-router';
+
+import router from '../src/router/router.js'
+
+
+Vue.config.productionTip = false
+
+
+// 安装 Vue Router 插件
+Vue.use(VueRouter);
+new Vue({
+ router, // 将路由器传递给 Vue 实例
+ render: h => h(App),
+}).$mount('#app')
diff --git a/kcui/src/router/router.js b/kcui/src/router/router.js
new file mode 100644
index 0000000..b61e5e3
--- /dev/null
+++ b/kcui/src/router/router.js
@@ -0,0 +1,25 @@
+//1.导入vue 和 vuerouter 的包
+import Vue from 'vue'
+import VueRouter from 'vue-router'
+import Home from '@/view/Home.vue'
+import Book from '@/view/Book.vue'
+
+//2.调用vue.use() 函数,把 VueRouter 安装为 Vue 的插件
+//vue.use()函数的作用,就是来安装插件的
+Vue.use(VueRouter)
+
+
+export default new VueRouter({
+ routes: [ //配置路由,这里是个数组
+ { //每一个链接都是一个对象
+ path: '/', //链接路径
+ name: 'Home', //路由名称,
+ component: Home //对应的组件模板
+ },
+ { //每一个链接都是一个对象
+ path: '/Book', //链接路径
+ name: 'Book', //路由名称,
+ component: Book //对应的组件模板
+ },
+]
+})
diff --git a/kcui/src/utils/auth.js b/kcui/src/utils/auth.js
new file mode 100644
index 0000000..aaa3b1c
--- /dev/null
+++ b/kcui/src/utils/auth.js
@@ -0,0 +1,14 @@
+// utils/auth.js
+import Cookies from 'js-cookie';
+
+export const setToken = (token) => {
+ Cookies.set('satoken', token, { expires: 7, secure: true, sameSite: 'strict' }); // Token有效期为7天
+};
+
+export const getToken = () => {
+ return Cookies.get('satoken');
+};
+
+export const removeToken = () => {
+ Cookies.remove('satoken');
+};
diff --git a/kcui/src/utils/request.js b/kcui/src/utils/request.js
new file mode 100644
index 0000000..b16a769
--- /dev/null
+++ b/kcui/src/utils/request.js
@@ -0,0 +1,137 @@
+import axios from 'axios';
+
+// import { ElMessage } from "element-ui";
+// import router from '../router/router';
+
+// create an axios instance
+const service = axios.create({
+ // baseURL: "http://127.0.0.1:10031/", // api 的 base_url
+ baseURL: "http://127.0.0.1:10031/", // api 的 base_urls
+ withCredentials: true,
+ timeout: 300000, // request timeout
+});
+
+// request interceptor
+service.interceptors.request.use(
+ (config) => {
+ //config.headers['token'] = Auth.getToken()
+ return config;
+ },
+ (error) => {
+ // Do something with request error
+ // console.log(error) // for debug
+ Promise.reject(error);
+ }
+);
+
+// response interceptor
+service.interceptors.response.use(
+ //response => response,
+ /**
+ * 下面的注释为通过在response里,自定义code来标示请求状态
+ * 当code返回如下情况则说明权限有问题,登出并返回到登录页
+ * 如想通过 xmlhttprequest 来状态码标识 逻辑可写在下面error中
+ * 以下代码均为样例,请结合自生需求加以修改,若不需要,则可删除
+ */
+ // response => {
+ // const res = response.data
+ // if (res.code !== 20000) {
+ // Message({
+ // message: res.message,
+ // type: 'error',
+ // duration: 5 * 1000
+ // })
+ // // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
+ // if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
+ // // 请自行在引入 MessageBox
+ // // import { Message, MessageBox } from 'element-ui'
+ // MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
+ // confirmButtonText: '重新登录',
+ // cancelButtonText: '取消',
+ // type: 'warning'
+ // }).then(() => {
+ // store.dispatch('FedLogOut').then(() => {
+ // location.reload() // 为了重新实例化vue-router对象 避免bug
+ // })
+ // })
+ // }
+ // return Promise.reject('error')
+ // } else {
+ // return response.data
+ // }
+ // },
+ (response) => {
+ let data;
+ // IE9时response.data是undefined,因此需要使用response.request.responseText(Stringify后的字符串)
+ if (response.data == undefined) {
+ data = JSON.parse(response.request.responseText);
+ } else {
+ data = response.data;
+ // const code = response.data.code
+ // if(code == '0') {
+ // data = response.data.data
+ // }else {
+ // Message({
+ // message: response.data.msg,
+ // type: 'error',
+ // duration: 5 * 1000
+ // })
+ // return Promise.reject('error')
+ // }
+ }
+ return data;
+ },
+ (error) => {
+ if (error && error.response) {
+ switch (error.response.status) {
+ case 400:
+ error.message = '数据请求错误';
+ break;
+ case 401:
+ error.message = '未授权,请登录';
+ break;
+ case 403:
+ error.message = '拒绝访问';
+ break;
+ case 404:
+ error.message = '请求地址出错';
+ break;
+ case 408:
+ error.message = '请求超时';
+ break;
+ case 500:
+ error.message = '服务器内部错误';
+ break;
+ case 501:
+ error.message = '服务未实现';
+ break;
+ case 502:
+ error.message = '网关错误';
+ break;
+ case 503:
+ error.message = '服务不可用';
+ break;
+ case 504:
+ error.message = '网关超时';
+ break;
+ case 505:
+ error.message = 'HTTP版本不受支持';
+ break;
+ default:
+ }
+ }
+ // ElMessage({
+ // message: error.message || '系统错误!',
+ // type: 'error',
+ // duration: 3 * 1000,
+ // });
+ // if (error.response.status == 403) {
+ // // eslint-disable-next-line no-undef
+ // clearAllSession();
+ // router.push('/');
+ // }
+ // return Promise.reject(error);
+ }
+);
+
+export default service;
diff --git a/kcui/src/utils/util.js b/kcui/src/utils/util.js
new file mode 100644
index 0000000..330ab23
--- /dev/null
+++ b/kcui/src/utils/util.js
@@ -0,0 +1,228 @@
+import Vue from "vue";
+let getevent = () => {
+ var Event = new Vue();
+ return Event;
+};
+const vueEvent = getevent();
+export { vueEvent };
+// 获取UUID
+export function getUUID() {
+ var s = [];
+ var hexDigits = '0123456789abcdef';
+ for (var i = 0; i < 36; i++) {
+ s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
+ }
+ s[14] = '4'; // bits 12-15 of the time_hi_and_version field to 0010
+ s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
+ s[8] = s[13] = s[18] = s[23] = '-';
+
+ var uuid = s.join('');
+ return uuid;
+}
+//本地存储
+export function getlocal(name) {
+ let data = localStorage.getItem(name);
+ if (data != null && data != '') {
+ try {
+ let obj = eval('(' + data + ')');
+ return obj;
+ } catch (e) {
+ return '';
+ }
+ } else {
+ return '';
+ }
+}
+export function getSession(name) {
+ let data = sessionStorage.getItem(name);
+ if (data != null && data != '') {
+ try {
+ let obj = eval('(' + data + ')');
+ return obj;
+ } catch (e) {
+ return '';
+ }
+ } else {
+ return '';
+ }
+}
+export function setLocal(key, value) {
+ window.localStorage.setItem(key, JSON.stringify(value));
+}
+export function setSession(key, value) {
+ window.sessionStorage.setItem(key, JSON.stringify(value));
+}
+export function clearOneLocal(key) {
+ window.localStorage.removeItem(key);
+}
+export function clearOneSession(key) {
+ window.sessionStorage.removeItem(key);
+}
+export function clearAllLocal() {
+ window.localStorage.clear();
+}
+export function clearAllSession() {
+ window.sessionStorage.clear();
+}
+// 时间格式化
+export function parseTime(time, cFormat) {
+ if (arguments.length === 0) {
+ return null;
+ }
+ const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}';
+ let date;
+ if (typeof time === 'object') {
+ date = time;
+ } else {
+ if (typeof time === 'string' && /^[0-9]+$/.test(time)) {
+ time = parseInt(time);
+ }
+ if (typeof time === 'number' && time.toString().length === 10) {
+ time = time * 1000;
+ }
+ date = new Date(time);
+ }
+ const formatObj = {
+ y: date.getFullYear(),
+ m: date.getMonth() + 1,
+ d: date.getDate(),
+ h: date.getHours(),
+ i: date.getMinutes(),
+ s: date.getSeconds(),
+ a: date.getDay(),
+ };
+ const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+ let value = formatObj[key];
+ // Note: getDay() returns 0 on Sunday
+ if (key === 'a') {
+ return ['日', '一', '二', '三', '四', '五', '六'][value];
+ }
+ if (result.length > 0 && value < 10) {
+ value = '0' + value;
+ }
+ return value || 0;
+ });
+ return time_str;
+}
+export function formatTime(time, option) {
+ if (('' + time).length === 10) {
+ time = parseInt(time) * 1000;
+ } else {
+ time = +time;
+ }
+ const d = new Date(time);
+ const now = Date.now();
+
+ const diff = (now - d) / 1000;
+
+ if (diff < 30) {
+ return '刚刚';
+ } else if (diff < 3600) {
+ // less 1 hour
+ return Math.ceil(diff / 60) + '分钟前';
+ } else if (diff < 3600 * 24) {
+ return Math.ceil(diff / 3600) + '小时前';
+ } else if (diff < 3600 * 24 * 2) {
+ return '1天前';
+ }
+ if (option) {
+ return parseTime(time, option);
+ } else {
+ return (
+ d.getMonth() + 1 + '月' + d.getDate() + '日' + d.getHours() + '时' + d.getMinutes() + '分'
+ );
+ }
+}
+//登录错误提示
+export function errortip(info) {
+ vueEvent.$message({
+ message: info,
+ type: 'error',
+ duration: '2000',
+ });
+}
+//成功提示
+export function successtip(info) {
+ vueEvent.$message({
+ message: info,
+ type: 'success',
+ duration: '2000',
+ });
+}
+//警告提示
+export function warningtip(info) {
+ vueEvent.$message({
+ message: info,
+ type: 'warning',
+ duration: '2000',
+ });
+}
+// 单位格式化
+export function numberFormat(value) {
+ var param = '';
+ var k = 10000,
+ sizes = ['', '万', '亿', '万亿'],
+ i;
+ if (value < k) {
+ param = value;
+ } else {
+ i = Math.floor(Math.log(value) / Math.log(k));
+ param = (value / Math.pow(k, i)).toFixed(1) + sizes[i];
+ }
+ return param;
+}
+// 数据格式化
+export function converdata(limit) {
+ limit = limit * 1;
+ var size = '';
+ if (limit < 1024) {
+ size = limit + 'KB';
+ } else if (limit < 1024 * 1024) {
+ size = (limit / 1024).toFixed(1) + 'MB';
+ } else if (limit < 1024 * 1024 * 1024) {
+ size = (limit / (1024 * 1024)).toFixed(1) + 'GB';
+ } else {
+ size = (limit / (1024 * 1024 * 1024)).toFixed(1) + 'TB';
+ }
+ return size;
+ // var sizestr = size + "";
+ // var len = sizestr.indexOf("\.");
+ // var dec = sizestr.substr(len + 1, 2);
+ // if(dec == "0"){//当小数点后为00时 去掉小数部分
+ // return sizestr.substring(0,len) + sizestr.substr(len + 3,2);
+ // }
+ // return sizestr;
+}
+// 单位格式化
+export function converunit(limit) {
+ limit = limit * 1;
+ var size = '';
+ if (limit < 1024) {
+ size = 'KB';
+ } else if (limit < 1024 * 1024) {
+ size = 'MB';
+ } else if (limit < 1024 * 1024 * 1024) {
+ size = 'GB';
+ } else {
+ size = 'TB';
+ }
+ return size;
+}
+// 颜色转换
+// export function colorRgb(color) {
+// var color = color.toLowerCase();
+// var pattern = /^#([0-9|a-f]{3}|[0-9|a-f]{6})$/;
+// if (color && pattern.test(color)) {
+// if (color.length == 4) {
+// // 将三位转换为六位
+// color = '#' + color[1] + color[1] + color[2] + color[2] + color[3] + color[3];
+// }
+// //处理六位的颜色值
+// var colorNew = [];
+// for (var i = 1; i < 7; i += 2) {
+// colorNew.push(parseInt('0x' + color.slice(i, i + 2)));
+// }
+// return colorNew.join(',');
+// }
+// return color;
+// }
diff --git a/kcui/src/view/Book.vue b/kcui/src/view/Book.vue
new file mode 100644
index 0000000..a7b68e9
--- /dev/null
+++ b/kcui/src/view/Book.vue
@@ -0,0 +1,274 @@
+
+
+
+
+
+
+ aaaaaaaaaaaaaaaaaaa{{num}}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/kcui/src/view/Home.vue b/kcui/src/view/Home.vue
new file mode 100644
index 0000000..bcbc787
--- /dev/null
+++ b/kcui/src/view/Home.vue
@@ -0,0 +1,276 @@
+
+
+
+
+
+
diff --git a/kcui/vue.config.js b/kcui/vue.config.js
new file mode 100644
index 0000000..910e297
--- /dev/null
+++ b/kcui/vue.config.js
@@ -0,0 +1,4 @@
+const { defineConfig } = require('@vue/cli-service')
+module.exports = defineConfig({
+ transpileDependencies: true
+})