sakuya/node_modules/neataptic/docs/js/articles/playground/graph.js

129 lines
4.2 KiB
JavaScript
Raw Normal View History

2022-04-10 00:37:53 +08:00
var NODE_RADIUS = 7;
var GATE_RADIUS = 2;
var REPEL_FORCE = 0;
var LINK_DISTANCE = 100;
var WIDTH = 500;
var HEIGHT = 600;
var d3cola = cola.d3adaptor()
.avoidOverlaps(true)
.size([WIDTH, HEIGHT]);
var drawGraph = function(graph, panel) {
var svg = d3.select(panel);
d3.selectAll(panel + "> *").remove();
// define arrow markers for graph links
svg.append('svg:defs').append('svg:marker')
.attr('id', 'end-arrow')
.attr('viewBox', '0 -5 10 10')
.attr('refX', 6)
.attr('markerWidth', 4)
.attr('markerHeight', 4)
.attr('orient', 'auto')
.append('svg:path')
.attr('d', 'M0,-5L10,0L0,5')
graph.nodes.forEach(function(v){
v.height = v.width = 2 * (v.name == 'GATE' ? GATE_RADIUS : NODE_RADIUS); }
);
d3cola
.nodes(graph.nodes)
.links(graph.links)
.constraints(graph.constraints)
.symmetricDiffLinkLengths(REPEL_FORCE)
.linkDistance(LINK_DISTANCE)
.start(10, 15, 20);
var path = svg.selectAll(".link")
.data(graph.links)
.enter().append('svg:path')
.attr('class', 'link')
path.append("title")
.text(function (d) {
var text = "";
text += "Weight: " + Math.round(d.weight*1000)/1000 + "\n";;
text += "Source: " + d.source.id + "\n";;
text += "Target: " + d.target.id;
return text;
});
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", function(d){
return "node " + d.name;
})
.attr("r", function(d) { return d.name == 'GATE' ? GATE_RADIUS : NODE_RADIUS; })
.call(d3cola.drag);
node.append("title")
.text(function (d){
var text = "";
text += "Activation: " + Math.round(d.activation*1000)/1000 + "\n";
text += "Bias: " + Math.round(d.bias*1000)/1000 + "\n";
text += "Position: " + d.id;
return text;
});
var label = svg.selectAll(".label")
.data(graph.nodes)
.enter().append("text")
.attr("class", "label")
.text(function (d){return '(' + d.index + ') ' + d.name; })
.call(d3cola.drag)
d3cola.on("tick", function () {
// draw directed edges with proper padding from node centers
path.attr('d', function (d) {
var deltaX = d.target.x - d.source.x,
deltaY = d.target.y - d.source.y,
dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY),
normX = deltaX / dist,
normY = deltaY / dist;
if(isNaN(normX)) normX = 0;
if(isNaN(normY)) normY = 0;
sourcePadding = d.source.width / 2,
targetPadding = d.target.width / 2 + 2,
sourceX = d.source.x + (sourcePadding * normX),
sourceY = d.source.y + (sourcePadding * normY),
targetX = d.target.x - (targetPadding * normX),
targetY = d.target.y - (targetPadding * normY);
// Defaults for normal edge.
drx = 0,
dry = 0,
xRotation = 0, // degrees
largeArc = 0, // 1 or 0
sweep = 1; // 1 or 0
// Self edge.
if (d.source.x === d.target.x && d.source.y === d.target.y) {
drx = dist;
dry = dist;
xRotation = -45;
largeArc = 1;
drx = 20;
dry = 20;
targetX = targetX + 1;
targetY = targetY + 1;
}
return 'M' + sourceX + ',' + sourceY + "A" + drx + "," + dry + " " + xRotation + "," + largeArc + "," + sweep + " " + targetX + ',' + targetY;
});
node.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
label
.attr("x", function (d) { return d.x + 10; })
.attr("y", function (d) { return d.y - 10; });
});
};