JSPlumb.js绘制关系拓扑图(力导向布局算法简单实现)

JSPlumb.js绘制关系拓扑图(力导向布局算法简单实现)

2023年7月9日发(作者:)

绘制关系拓扑图(⼒导向布局算法简单实现) 绘制关系拓扑图(⼒导向布局算法简单实现)随机⽣成结点 与结点的位置 /** * A force directed graph layout implementation by liuchang on 2018/05/10. */ const CANVAS_WIDTH = 1000; const CANVAS_HEIGHT = 1000; let k; let mNodeList = []; let mEdgeList = []; let mDxMap = {}; let mDyMap = {}; let mNodeMap = {}; var json ={} ;function ForceDirected() { //generate nodes and edges for (let i = 0; i < 20; i++) { (new Node(i)); } for (let i = 0; i < 20; i++) { let edgeCount = () * 8 + 1; for (let j = 0; j < edgeCount; j++) { let targetId = (() * 20); let edge = new Edge(i, targetId); (edge); } } if (mNodeList && mEdgeList) { k = (CANVAS_WIDTH * CANVAS_HEIGHT / ); } for (let i = 0; i < ; i++) { let node = mNodeList[i]; if (node) { mNodeMap[] = node; } } //随机⽣成坐标. Generate coordinates randomly. let initialX, initialY, initialSize = 40.0; for (let i in mNodeList) { initialX = CANVAS_WIDTH * .5; initialY = CANVAS_HEIGHT * .5; mNodeList[i].x = initialX + initialSize * (() - .5); mNodeList[i].y = initialY + initialSize * (() - .5); } //迭代200次. Iterate 200 times. for (let i = 0; i < 200; i++) { calculateRepulsive(); calculateTraction(); updateCoordinates(); }

json = ify(new Result(mNodeList, mEdgeList)); //();

}function Node(id = null) { = id; this.x = 22; this.y = null;}function Edge(source = null, target = null) { = source; = target;}/** *

计算两个Node的斥⼒产⽣的单位位移。 * Calculate the displacement generated by the repulsive force between two nodes.* */function calculateRepulsive() { let ejectFactor = 6; let distX, distY, dist; for (let i = 0; i < ; i++) { mDxMap[mNodeList[i].id] = 0.0; mDyMap[mNodeList[i].id] = 0.0; for (let j = 0; j < ; j++) { if (i !== j) { distX = mNodeList[i].x - mNodeList[j].x; distY = mNodeList[i].y - mNodeList[j].y; dist = (distX * distX + distY * distY); } if (dist < 30) { ejectFactor = 5; } if (dist > 0 && dist < 250) { let id = mNodeList[i].id; mDxMap[id] = mDxMap[id] + distX / dist * k * k / dist * ejectFactor; mDyMap[id] = mDyMap[id] + distY / dist * k * k / dist * ejectFactor; } } }}/** *

计算Edge的引⼒对两端Node产⽣的引⼒。 * Calculate the traction force generated by the edge acted on the two nodes of its two ends. */function calculateTraction() { let condenseFactor = 3; let startNode, endNode; for (let e = 0; e < ; e++) { let eStartID = mEdgeList[e].source; let eEndID = mEdgeList[e].target; startNode = mNodeMap[eStartID]; endNode = mNodeMap[eEndID]; if (!startNode) { ("Cannot find start node id: " + eStartID + ", please check it out."); return; } if (!endNode) { ("Cannot find end node id: " + eEndID + ", please check it out."); return; } let distX, distY, dist; distX = startNode.x - endNode.x; distY = startNode.y - endNode.y; dist = (distX * distX + distY * distY); mDxMap[eStartID] = mDxMap[eStartID] - distX * dist / k * condenseFactor; mDyMap[eStartID] = mDyMap[eStartID] - distY * dist / k * condenseFactor; mDxMap[eEndID] = mDxMap[eEndID] + distX * dist / k * condenseFactor; mDyMap[eEndID] = mDyMap[eEndID] + distY * dist / k * condenseFactor; } }}/** *

更新坐标。 * update the coordinates. */function updateCoordinates() { let maxt = 4, maxty = 3; //Additional coefficients. for (let v = 0; v < ; v++) { let node = mNodeList[v]; let dx = (mDxMap[]); let dy = (mDyMap[]); if (dx < -maxt) dx = -maxt; if (dx > maxt) dx = maxt; if (dy < -maxty) dy = -maxty; if (dy > maxty) dy = maxty; node.x = node.x + dx >= CANVAS_WIDTH || node.x + dx <= 0 ? node.x - dx : node.x + dx; node.y = node.y + dy >= CANVAS_HEIGHT || node.y + dy <= 0 ? node.y - dy : node.y + dy; }}function Result(nodes = null, links = null) { = nodes; = links;}产⽣的json数据 {"nodes":[{"id":0,"x":253.8,"y":252.69},{"id":1,"x":385.47,"y":621.2774375590121},{"id":2,"x":785.76,"y":385.22},{"id":3,"x":405.77265246315744,"y":758.9663294857901},{"id":4,"x":387.42566167935115,"y":375.9496386440198},{"id":5,"x":636.2256279616934,"y":650.27},{"id":6,"x":903.57,"y":473.844},{"id":7,"x":629.6,"y":417.6638952006809},{"id":8,"x":823.6644385662,"y":707.3},{"id":9,"x":684.93,"y":343.37841641501205},{"id":10,"x":664.9,"y":738.36},{"id":11,"x":538.1,"y":416.53344738862125},{"id":12,"x":528.4,"y":646.4668782641444},{"id":13,"x":723.83,"y":495.39},{"id":14,"x":556.9332189690231,"y":297.142},{"id":15,"x":507.85974528045915,"y":536.5949966440751},{"id":16,"x":496.195,"y":196.28},{"id":17,"x":398.2,"y":486.6329335530637},{"id":18,"x":638.639,"y":526.74},{"id":19,"x":865.8762559421327,"y":567.68}],"links":[{"source":0,"target":14},{"source":0,"target":17},{"source":1,"target":2},{"source":1,"target":18},{"source":1,"target":1},{"source":2,"target":6},{"source":2,"target":11},{"source":2,"target":13},{"source":2,"target":11},{"source":2,"target":18},{"source":2,"target":9},{"source":3,"target":12},{"source":3,"target":1},{"source":3,"target":15},{"source":3,"target":10},{"source":3,"target":12},{"source":4,"target":9},{"source":4,"target":3},{"source":5,"target":9},{"source":5,"target":15},{"source":5,"target":13},{"source":5,"target":12},{"source":5,"target":12},{"source":5,"target":12},{"source":5,"target":13},{"source":5,"target":10},{"source":5,"target":7},{"source":6,"target":18},{"source":6,"target":2},{"source":6,"target":19},{"source":6,"target":8},{"source":6,"target":19},{"source":6,"target":2},{"source":6,"target":10},{"source":7,"target":6},{"source":7,"target":15},{"source":7,"target":7},{"source":7,"target":17},{"source":7,"target":19},{"source":8,"target":5},{"source":8,"target":10},{"source":8,"target":2},{"source":9,"target":13},{"source":9,"target":15},{"source":9,"target":12},{"source":9,"target":6},{"source":9,"target":14},{"source":10,"target":1},{"source":10,"target":13},{"source":10,"target":8},{"source":10,"target":9},{"source":11,"target":4},{"source":11,"target":11},{"source":11,"target":18},{"source":11,"target":7},{"source":11,"target":14},{"source":11,"target":7},{"source":11,"target":17},{"source":12,"target":5},{"source":12,"target":7},{"source":12,"target":14},{"source":12,"target":10},{"source":12,"target":11},{"source":12,"target":17},{"source":12,"target":8},{"source":12,"target":3},{"source":12,"target":14},{"source":13,"target":16},{"source":13,"target":4},{"source":13,"target":13},{"source":13,"target":8},{"source":13,"target":15},{"source":13,"target":18},{"source":13,"target":19},{"source":14,"target":9},{"source":14,"target":16},{"source":14,"target":16},{"source":15,"target":4},{"source":15,"target":7},{"source":15,"target":10},{"source":15,"target":1},{"source":15,"target":9},{"source":15,"target":11},{"source":16,"target":7},{"source":16,"target":18},{"source":16,"target":16},{"source":16,"target":14},{"source":16,"target":4},{"source":16,"target":0},{"source":16,"target":11},{"source":17,"target":15},{"source":17,"target":3},{"source":17,"target":13},{"source":17,"target":4},{"source":17,"target":12},{"source":17,"target":1},{"source":17,"target":5},{"source":17,"target":7},{"source":17,"target":14},{"source":18,"target":11},{"source":18,"target":2},{"source":18,"target":17},{"source":18,"target":11},{"source":18,"target":8},{"source":18,"target":7},{"source":18,"target":11},{"source":18,"target":7},{"source":19,"target":6},{"source":19,"target":14},{"source":19,"target":8},{"source":19,"target":11},{"source":19,"target":2},{"source":19,"target":19}]}获得结点坐标与结点⽗⼦关系后 绘制拓扑图 ForceDirected(); (json); json = (json);

//⽣成div for(var i = 0; i<20 ; i++){

var x = json["nodes"][i]["x"]; var y = json["nodes"][i]["y"]; var div = '

'+ '
'+ ''+i+''+ '
'+ '
';

$("#canvas").append(div); var next = i + 1; add2Group("database_"+i,"databasegroup_"+i,"service_"+i,j); }

$.each(json["links"],function(index,link){

var sourceId = link["source"]; var target = link["target"];

connectA2B(elector("#database_"+sourceId),elector("#service_"+target),j );

}); function connectA2B(a,b,j){

// connect some before configuring group t({ source: a, target: b, anchors:["Right","Left"], endpoint: ["Dot", {radius: 1}], overlays: [ ["Arrow", { width: 5, length:5, location: 1, id: "arrow" } ] ], paintStyle : { strokeWidth : 1, stroke : "#456" }//连线样式 });

}

function add2Group( groupId,groupName,divId,j){

up({ el: elector("#"+groupId), id: groupName, dropOverride: true, endpoint: ["Dot", {radius: 3}]// droppable:false }); //(the default is to revert)

roup(groupName,elector("#"+divId));

}最终效果图20个结点两百次迭代的效果图,没想到离开了学校还是要和物理打交道,万物皆可做模型。

发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1688906935a182263.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信