Published
Edited
Oct 9, 2021
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
graph = {
bDisplayContext;
bDisplayLabeledContext;

let graph = {
nodes: [],
links: []
};

for (let i = 0; i < numberOfNodes; i++) {
graph.nodes.push({
id: i,
name: i + 1 + "",
width: 60,
height: 40,
visible: true,
relativeX: 0,
relativeY: 5
});

for (let j = i + 1; j < numberOfNodes; j++) {
graph.links.push({ source: i, target: j, visible: true });
}
}
svgs.selectAll(".cleanOnInit").remove();
return graph;
}
Insert cell
computeTorusLayout = (
graph,
twoEdgeWrappingGraph,
threeEdgeWrappingGraph,
bEdgeWrappingConfig,
boundaryConfig
) => {
if (
twoEdgeWrappingGraph != null &&
twoEdgeWrappingGraph.links != null &&
twoEdgeWrappingGraph.nodes != null
) {
//restore visibility of edges on graph
//overwrite all the wrapping edges derived in previous layout round
graph.links.forEach(d => {
d.visible = true;
});

graph.links.forEach(d => {
if (d.source.visible && d.target.visible) d.visible = true;
else d.visible = false;
});
twoEdgeWrappingGraph.nodes.splice(0, twoEdgeWrappingGraph.nodes.length);
twoEdgeWrappingGraph.links.splice(0, twoEdgeWrappingGraph.links.length);
threeEdgeWrappingGraph.nodes.splice(0, threeEdgeWrappingGraph.nodes.length);
threeEdgeWrappingGraph.links.splice(0, threeEdgeWrappingGraph.links.length);
wrappingNodeLabel.splice(0, wrappingNodeLabel.length);

for (let node of graph.nodes) {
if (node.visible) {
twoEdgeWrappingGraph.nodes.push({
x: node.x,
y: node.y,
visible: false,
name: ""
});
threeEdgeWrappingGraph.nodes.push({
x: node.x,
y: node.y,
visible: false,
name: ""
});
}
}
}
let sourceX = 0;
let sourceY = 0;
let targetX = 0;
let targetY = 0;
let mappingNodes = null;
let intersectionPoints = null;
let tmpDistance = 0;
let edgeLength;

for (let edge of graph.links) {
if (edge.visible) {
sourceX = edge.source.x;
sourceY = edge.source.y;
targetX = edge.target.x;
targetY = edge.target.y;
edgeLength = { value: 0 };
tmpDistance = 0;

mappingNodes = findMappingNodesFromOtherSquares(
targetX,
targetY,
boundaryConfig
);
intersectionPoints = findIntersectionPointsWithShortestEdgeBtnSourceAndTarget(
sourceX,
sourceY,
targetX,
targetY,
mappingNodes,
edgeLength,
bEdgeWrappingConfig,
boundaryConfig
);
tmpDistance = findEuclideanDistance(sourceX, sourceY, targetX, targetY);

if (
edgeLength.value < tmpDistance &&
intersectionPoints != null &&
intersectionPoints.length > 0
) {
if (intersectionPoints.length > 2 && intersectionPoints.length < 5) {
threeEdgeWrappingGraph.nodes.push({
x: intersectionPoints[0].x,
y: intersectionPoints[0].y,
visible: true,
name: edge.target.name
});
threeEdgeWrappingGraph.nodes.push({
x: intersectionPoints[1].x,
y: intersectionPoints[1].y,
visible: true,
name: edge.source.name
});
threeEdgeWrappingGraph.links.push({
x1: intersectionPoints[0].x,
y1: intersectionPoints[0].y,
x2: sourceX,
y2: sourceY,
visible: true
});
threeEdgeWrappingGraph.links.push({
x1: intersectionPoints[1].x,
y1: intersectionPoints[1].y,
x2: targetX,
y2: targetY,
visible: true
});

threeEdgeWrappingGraph.nodes.push({
x: intersectionPoints[2].x,
y: intersectionPoints[2].y,
visible: true
});
threeEdgeWrappingGraph.nodes.push({
x: intersectionPoints[3].x,
y: intersectionPoints[3].y,
visible: true
});
threeEdgeWrappingGraph.links.push({
x1: intersectionPoints[2].x,
y1: intersectionPoints[2].y,
x2: intersectionPoints[3].x,
y2: intersectionPoints[3].y,
visible: true
});

mutable wrappingNodeLabel.push({
x: intersectionPoints[0].x,
y: intersectionPoints[0].y,
visible: true,
name: edge.target.name
});
mutable wrappingNodeLabel.push({
x: intersectionPoints[1].x,
y: intersectionPoints[1].y,
visible: true,
name: edge.source.name
});
} else {
twoEdgeWrappingGraph.nodes.push({
x: intersectionPoints[0].x,
y: intersectionPoints[0].y,
visible: true,
name: edge.target.name
});
twoEdgeWrappingGraph.nodes.push({
x: intersectionPoints[1].x,
y: intersectionPoints[1].y,
visible: true,
name: edge.source.name
});
twoEdgeWrappingGraph.links.push({
x1: intersectionPoints[0].x,
y1: intersectionPoints[0].y,
x2: sourceX,
y2: sourceY,
visible: true
});
twoEdgeWrappingGraph.links.push({
x1: intersectionPoints[1].x,
y1: intersectionPoints[1].y,
x2: targetX,
y2: targetY,
visible: true
});

mutable wrappingNodeLabel.push({
x: intersectionPoints[0].x,
y: intersectionPoints[0].y,
visible: true,
name: edge.target.name
});
mutable wrappingNodeLabel.push({
x: intersectionPoints[1].x,
y: intersectionPoints[1].y,
visible: true,
name: edge.source.name
});
}
edge.visible = false;
}
}
mutable numberOfTwoEdgeWrappingLinks = 0;
twoEdgeWrappingGraph.links.forEach(d => {
mutable numberOfTwoEdgeWrappingLinks++;
});

mutable numberOfThreeEdgeWrappingLinks = 0;
threeEdgeWrappingGraph.links.forEach(d => {
mutable numberOfThreeEdgeWrappingLinks++;
});
}

mutable numberOfNonWrappingLinks = 0;
graph.links.forEach(d => {
if (d.visible) mutable numberOfNonWrappingLinks++;
});
}
Insert cell
findMappingNodesFromOtherSquares = (x, y, boundaryConfig) => {
//initialise mapping array
let mappingNodes = new Array();

if (
x < boundaryConfig.oneThirdWidth &&
x > boundaryConfig.twoThirdsWidth &&
y < boundaryConfig.oneThirdHeight &&
y > boundaryConfig.twoThirdsHeight
)
mappingNodes = null;

if (mappingNodes != null) {
//calculate x, y position of nodes in the 4 adjacent squares
//in the order of [left, up, right, bottom]
mappingNodes.push({
x: x - boundaryConfig.oneThirdWidth,
y: y,
intersectedX: boundaryConfig.oneThirdWidth,
intersectedY: 0
});
mappingNodes.push({
x: x,
y: y - boundaryConfig.oneThirdHeight,
intersectedX: 0,
intersectedY: boundaryConfig.oneThirdHeight
});
mappingNodes.push({
x: x + boundaryConfig.oneThirdWidth,
y: y,
intersectedX: boundaryConfig.twoThirdsWidth,
intersectedY: 0
});
mappingNodes.push({
x: x,
y: y + boundaryConfig.oneThirdHeight,
intersectedX: 0,
intersectedY: boundaryConfig.twoThirdsHeight
});

//calculate x, y position of nodes in the 4 corner squares
//in the order of [upper-left, upper-right, bottom-right bottom-left]
mappingNodes.push({
x: x - boundaryConfig.oneThirdWidth,
y: y - boundaryConfig.oneThirdHeight,
intersectedX: boundaryConfig.oneThirdWidth,
intersectedY: boundaryConfig.oneThirdHeight
});
mappingNodes.push({
x: x + boundaryConfig.oneThirdWidth,
y: y - boundaryConfig.oneThirdHeight,
intersectedX: boundaryConfig.twoThirdsWidth,
intersectedY: boundaryConfig.oneThirdHeight
});
mappingNodes.push({
x: x + boundaryConfig.oneThirdWidth,
y: y + boundaryConfig.oneThirdHeight,
intersectedX: boundaryConfig.twoThirdsWidth,
intersectedY: boundaryConfig.twoThirdsHeight
});
mappingNodes.push({
x: x - boundaryConfig.oneThirdWidth,
y: y + boundaryConfig.oneThirdHeight,
intersectedX: boundaryConfig.oneThirdWidth,
intersectedY: boundaryConfig.twoThirdsHeight
});
}
return mappingNodes;
}
Insert cell
findIntersectionPointsWithShortestEdgeBtnSourceAndTarget = (
sourceX,
sourceY,
targetX,
targetY,
mappingNodes,
edgeLength,
bEdgeWrappingConfig,
boundaryConfig
) => {
let intersectionPoints = new Array();
let shortestEuclideanDistance = Number.MAX_VALUE;

//ignore if mappingNodes is null or empty
if (mappingNodes == null) intersectionPoints = null;
else {
for (let mappingNode of mappingNodes) {
let intersectedX1 = 0;
let intersectedY1 = 0;
let intersectedX2 = 0;
let intersectedY2 = 0;
let intersectedX3 = 0;
let intersectedY3 = 0;
let intersectedX4 = 0;
let intersectedY4 = 0;

//if intersection resides in a corner square, check which of the two sides of the the boundary it intersects
if (
mappingNode.intersectedX != 0 &&
mappingNode.intersectedY != 0 &&
bEdgeWrappingConfig[1]
) {
//upper-left corner
if (
mappingNode.intersectedX == boundaryConfig.oneThirdWidth &&
mappingNode.intersectedY == boundaryConfig.oneThirdHeight
) {
let testX1 = mappingNode.intersectedX;
let testY1 = getYGivenXAndSrcMappingNodes(
sourceX,
sourceY,
mappingNode.x,
mappingNode.y,
mappingNode.intersectedX
);

let testY2 = mappingNode.intersectedY;
let testX2 = getXGivenYAndSrcMappingNodes(
sourceX,
sourceY,
mappingNode.x,
mappingNode.y,
mappingNode.intersectedY
);

//check whether testY1 is within center square boundary
if (
testY1 >= boundaryConfig.oneThirdHeight &&
testY1 <= boundaryConfig.twoThirdsHeight
) {
intersectedX1 = mappingNode.intersectedX;
intersectedY1 = testY1;

intersectedX2 = testX2 + boundaryConfig.oneThirdWidth;
intersectedY2 = testY2 + boundaryConfig.oneThirdHeight;

intersectedX3 = intersectedX1 + boundaryConfig.oneThirdWidth;
intersectedY3 = intersectedY1;

intersectedX4 = testX2 + boundaryConfig.oneThirdWidth;
intersectedY4 = testY2;
} else if (
testX2 >= boundaryConfig.oneThirdWidth &&
testX2 <= boundaryConfig.twoThirdsWidth
) {
intersectedX1 = testX2;
intersectedY1 = mappingNode.intersectedY;

intersectedX2 = testX1 + boundaryConfig.oneThirdWidth;
intersectedY2 = testY1 + boundaryConfig.oneThirdHeight;

intersectedX3 = intersectedX1;
intersectedY3 = intersectedY1 + boundaryConfig.oneThirdHeight;

intersectedX4 = testX1;
intersectedY4 = testY1 + boundaryConfig.oneThirdHeight;
}
}
//upper-right corner
else if (
mappingNode.intersectedX == boundaryConfig.twoThirdsWidth &&
mappingNode.intersectedY == boundaryConfig.oneThirdHeight
) {
let testX1 = mappingNode.intersectedX;
let testY1 = getYGivenXAndSrcMappingNodes(
sourceX,
sourceY,
mappingNode.x,
mappingNode.y,
mappingNode.intersectedX
);

let testY2 = mappingNode.intersectedY;
let testX2 = getXGivenYAndSrcMappingNodes(
sourceX,
sourceY,
mappingNode.x,
mappingNode.y,
mappingNode.intersectedY
);

//check whether testY1 is within center square boundary
if (
testY1 >= boundaryConfig.oneThirdHeight &&
testY1 <= boundaryConfig.twoThirdsHeight
) {
intersectedX1 = mappingNode.intersectedX;
intersectedY1 = testY1;

intersectedX2 = testX2 - boundaryConfig.oneThirdWidth;
intersectedY2 = testY2 + boundaryConfig.oneThirdHeight;

intersectedX3 = intersectedX1 - boundaryConfig.oneThirdWidth;
intersectedY3 = intersectedY1;

intersectedX4 = testX2 - boundaryConfig.oneThirdWidth;
intersectedY4 = testY2;
} else if (
testX2 >= boundaryConfig.oneThirdWidth &&
testX2 <= boundaryConfig.twoThirdsWidth
) {
intersectedX1 = testX2;
intersectedY1 = mappingNode.intersectedY;

intersectedX2 = testX1 - boundaryConfig.oneThirdWidth;
intersectedY2 = testY1 + boundaryConfig.oneThirdHeight;

intersectedX3 = intersectedX1;
intersectedY3 = intersectedY1 + boundaryConfig.oneThirdHeight;

intersectedX4 = testX1;
intersectedY4 = testY1 + boundaryConfig.oneThirdHeight;
}
}
//bottom-right corner
else if (
mappingNode.intersectedX == boundaryConfig.twoThirdsWidth &&
mappingNode.intersectedY == boundaryConfig.twoThirdsHeight
) {
let testX1 = mappingNode.intersectedX;
let testY1 = getYGivenXAndSrcMappingNodes(
sourceX,
sourceY,
mappingNode.x,
mappingNode.y,
mappingNode.intersectedX
);

let testY2 = mappingNode.intersectedY;
let testX2 = getXGivenYAndSrcMappingNodes(
sourceX,
sourceY,
mappingNode.x,
mappingNode.y,
mappingNode.intersectedY
);

//check whether testY1 is within center square boundary
if (
testY1 >= boundaryConfig.oneThirdHeight &&
testY1 <= boundaryConfig.twoThirdsHeight
) {
intersectedX1 = mappingNode.intersectedX;
intersectedY1 = testY1;

intersectedX2 = testX2 - boundaryConfig.oneThirdWidth;
intersectedY2 = testY2 - boundaryConfig.oneThirdHeight;

intersectedX3 = intersectedX1 - boundaryConfig.oneThirdWidth;
intersectedY3 = intersectedY1;

intersectedX4 = testX2 - boundaryConfig.oneThirdWidth;
intersectedY4 = testY2;
} else if (
testX2 >= boundaryConfig.oneThirdWidth &&
testX2 <= boundaryConfig.twoThirdsWidth
) {
intersectedX1 = testX2;
intersectedY1 = mappingNode.intersectedY;

intersectedX2 = testX1 - boundaryConfig.oneThirdWidth;
intersectedY2 = testY1 - boundaryConfig.oneThirdHeight;

intersectedX3 = intersectedX1;
intersectedY3 = intersectedY1 - boundaryConfig.oneThirdHeight;

intersectedX4 = testX1;
intersectedY4 = testY1 - boundaryConfig.oneThirdHeight;
}
}
//bottom-left corner
else if (
mappingNode.intersectedX == boundaryConfig.oneThirdWidth &&
mappingNode.intersectedY == boundaryConfig.twoThirdsHeight
) {
let testX1 = mappingNode.intersectedX;
let testY1 = getYGivenXAndSrcMappingNodes(
sourceX,
sourceY,
mappingNode.x,
mappingNode.y,
mappingNode.intersectedX
);

let testY2 = mappingNode.intersectedY;
let testX2 = getXGivenYAndSrcMappingNodes(
sourceX,
sourceY,
mappingNode.x,
mappingNode.y,
mappingNode.intersectedY
);

//check whether testY1 is within center square boundary
if (
testY1 >= boundaryConfig.oneThirdHeight &&
testY1 <= boundaryConfig.twoThirdsHeight
) {
intersectedX1 = mappingNode.intersectedX;
intersectedY1 = testY1;

intersectedX2 = testX2 + boundaryConfig.oneThirdWidth;
intersectedY2 = testY2 - boundaryConfig.oneThirdHeight;

intersectedX3 = intersectedX1 + boundaryConfig.oneThirdWidth;
intersectedY3 = intersectedY1;

intersectedX4 = testX2 + boundaryConfig.oneThirdWidth;
intersectedY4 = testY2;
} else if (
testX2 >= boundaryConfig.oneThirdWidth &&
testX2 <= boundaryConfig.twoThirdsWidth
) {
intersectedX1 = testX2;
intersectedY1 = mappingNode.intersectedY;

intersectedX2 = testX1 + boundaryConfig.oneThirdWidth;
intersectedY2 = testY1 - boundaryConfig.oneThirdHeight;

intersectedX3 = intersectedX1;
intersectedY3 = intersectedY1 - boundaryConfig.oneThirdHeight;

intersectedX4 = testX1;
intersectedY4 = testY1 - boundaryConfig.oneThirdHeight;
}
}
} else if (mappingNode.intersectedX != 0 && bEdgeWrappingConfig[0]) {
intersectedX1 = mappingNode.intersectedX;
intersectedY1 = getYGivenXAndSrcMappingNodes(
sourceX,
sourceY,
mappingNode.x,
mappingNode.y,
mappingNode.intersectedX
);
intersectedX2 =
mappingNode.intersectedX == boundaryConfig.oneThirdWidth
? boundaryConfig.twoThirdsWidth
: boundaryConfig.oneThirdWidth;
intersectedY2 = intersectedY1;
} else if (mappingNode.intersectedY != 0 && bEdgeWrappingConfig[0]) {
intersectedY1 = mappingNode.intersectedY;
intersectedX1 = getXGivenYAndSrcMappingNodes(
sourceX,
sourceY,
mappingNode.x,
mappingNode.y,
mappingNode.intersectedY
);

intersectedX2 = intersectedX1;
intersectedY2 =
mappingNode.intersectedY == boundaryConfig.oneThirdHeight
? boundaryConfig.twoThirdsHeight
: boundaryConfig.oneThirdHeight;
}
let tmpDistanceBtnSourceAndIntersectPt1 = findEuclideanDistance(
intersectedX1,
intersectedY1,
sourceX,
sourceY
);
let tmpDistanceBtnTargetAndIntersectPt2 = findEuclideanDistance(
intersectedX2,
intersectedY2,
targetX,
targetY
);

let sumOfTwoEdgeSegmentLength =
tmpDistanceBtnSourceAndIntersectPt1 +
tmpDistanceBtnTargetAndIntersectPt2;

//compute sum of two edge segment for wrapping on adjacent squares
if (
bEdgeWrappingConfig[0] &&
(mappingNode.intersectedX == 0 || mappingNode.intersectedY == 0) &&
shortestEuclideanDistance > sumOfTwoEdgeSegmentLength
) {
if (mappingNode.intersectedX != 0 || mappingNode.intersectedY != 0) {
shortestEuclideanDistance = sumOfTwoEdgeSegmentLength;
edgeLength.value = shortestEuclideanDistance;
intersectionPoints.splice(0, intersectionPoints.length);
intersectionPoints.push({ x: intersectedX1, y: intersectedY1 });
intersectionPoints.push({ x: intersectedX2, y: intersectedY2 });
}
}
//compute sum of three edge segment for wrapping on corner squares
else if (
bEdgeWrappingConfig[1] &&
(mappingNode.intersectedX != 0 && mappingNode.intersectedY != 0) &&
shortestEuclideanDistance > sumOfTwoEdgeSegmentLength
) {
let tmpDistanceBtnIntersectPt3Pt4 = findEuclideanDistance(
intersectedX3,
intersectedY3,
intersectedX4,
intersectedY4
);
if (
shortestEuclideanDistance >
tmpDistanceBtnIntersectPt3Pt4 + sumOfTwoEdgeSegmentLength
) {
shortestEuclideanDistance =
tmpDistanceBtnIntersectPt3Pt4 + sumOfTwoEdgeSegmentLength;
edgeLength.value = shortestEuclideanDistance;
intersectionPoints.splice(0, intersectionPoints.length);
intersectionPoints.push({ x: intersectedX1, y: intersectedY1 });
intersectionPoints.push({ x: intersectedX2, y: intersectedY2 });
intersectionPoints.push({ x: intersectedX3, y: intersectedY3 });
intersectionPoints.push({ x: intersectedX4, y: intersectedY4 });
}
}
}
}
return intersectionPoints;
}
Insert cell
getYGivenXAndSrcMappingNodes = (x1, y1, x2, y2, x) => {
let y = 0;
if(x1 == x2)
y = (y1+y2)/2;
else {
y = (x2*y1-x*y1-x1*y2+x*y2)/(x2-x1);
}
return y;
}
Insert cell
getXGivenYAndSrcMappingNodes = (x1, y1, x2, y2, y) => {
let x = 0;
if(y1 == y2)
x = (x1+x2)/2;
else {
x = (x1*y2-x2*y1-x1*y+x2*y)/(y2-y1);
}
return x;
}
Insert cell
findEuclideanDistance = (x1, y1, x2, y2) => {
return Math.sqrt(Math.pow(x1-x2,2) + Math.pow(y1-y2,2));
}
Insert cell
boundaryConfig = ({
"oneThirdWidth": configuration.svgWidth/3,
"twoThirdsWidth": configuration.svgWidth*2/3,
"oneThirdHeight": configuration.svgHeight/3,
"twoThirdsHeight": configuration.svgHeight*2/3
});
Insert cell
boundary = {
let boundary = new Array();
boundary.push({"x1":boundaryConfig.oneThirdWidth, "y1":0, "x2":boundaryConfig.oneThirdWidth, "y2":configuration.svgHeight, "strokeWidth":1});
boundary.push({"x1":boundaryConfig.twoThirdsWidth, "y1":0, "x2":boundaryConfig.twoThirdsWidth, "y2":configuration.svgHeight, "strokeWidth":1});
boundary.push({"x1":0, "y1":boundaryConfig.oneThirdHeight, "x2":configuration.svgWidth, "y2":boundaryConfig.oneThirdHeight, "strokeWidth":1});
boundary.push({"x1":0, "y1":boundaryConfig.twoThirdsHeight, "x2":configuration.svgWidth, "y2":boundaryConfig.twoThirdsHeight, "strokeWidth":1});
boundary.push({"x1":boundaryConfig.oneThirdWidth, "y1":boundaryConfig.oneThirdHeight, "x2":boundaryConfig.twoThirdsWidth, "y2":boundaryConfig.oneThirdHeight, "strokeWidth":5});
boundary.push({"x1":boundaryConfig.oneThirdWidth, "y1":boundaryConfig.twoThirdsHeight, "x2":boundaryConfig.twoThirdsWidth, "y2":boundaryConfig.twoThirdsHeight, "strokeWidth":5});
return boundary;
}
Insert cell
verticalBoundary = {
let verticalBoundary = new Array();
verticalBoundary.push({"x1":boundaryConfig.oneThirdWidth, "y1":boundaryConfig.oneThirdHeight, "x2":boundaryConfig.oneThirdWidth, "y2":boundaryConfig.twoThirdsHeight, "strokeWidth":5});
verticalBoundary.push({"x1":boundaryConfig.twoThirdsWidth, "y1":boundaryConfig.oneThirdHeight, "x2":boundaryConfig.twoThirdsWidth, "y2":boundaryConfig.twoThirdsHeight, "strokeWidth":5});
return verticalBoundary;
}
Insert cell
draggableVerticalBoundary = {
let draggableVerticalBoundary = svgs
.selectAll(".verticalBourndary")
.data(verticalBoundary)
.enter()
.append("line")
.attr("x1", d => {
return d.x1;
})
.attr("y1", d => {
return d.y1;
})
.attr("x2", d => {
return d.x2;
})
.attr("y2", d => {
return d.y2;
})
.attr("class", "bourndary" + " cleanOnInit")
.style("stroke", "#BED7F6")
.style("stroke-width", d => {
return d.strokeWidth;
})
.call(
d3
.drag()
.on('start', () => {
draggableBorderConfig.dragStartX = d3.event.x;
draggableBorderConfig.dragStartY = d3.event.y;
/** Preventing propagation of dragstart to parent elements */
d3.event.sourceEvent.stopPropagation();
})
.on('drag', () => {
configuration.svgWidth +=
d3.event.x - draggableBorderConfig.dragStartX;
configuration.svgHeight = configuration.svgWidth;
draggableBorderConfig.dragStartX = d3.event.x;
draggableBorderConfig.dragStartY = d3.event.x;
border[0] = {
x1: 0,
y1: 0,
x2: configuration.svgWidth,
y2: 0,
strokeWidth: 1
};
border[1] = {
x1: 0,
y1: 0,
x2: 0,
y2: configuration.svgHeight,
strokeWidth: 1
};
horizontalBorder[0] = {
x1: 0,
y1: configuration.svgHeight,
x2: configuration.svgWidth,
y2: configuration.svgHeight,
strokeWidth: 1
};
verticalBorder[0] = {
x1: configuration.svgWidth,
y1: 0,
x2: configuration.svgWidth,
y2: configuration.svgHeight,
strokeWidth: 1
};
boundaryConfig.oneThirdWidth = configuration.svgWidth / 3;
boundaryConfig.twoThirdsWidth = (configuration.svgWidth * 2) / 3;
boundaryConfig.oneThirdHeight = configuration.svgHeight / 3;
boundaryConfig.twoThirdsHeight = (configuration.svgHeight * 2) / 3;

mutable centerSquareWidth = configuration.svgWidth;
mutable centerSquareHeight = configuration.svgHeight;
boundary[0] = {
x1: boundaryConfig.oneThirdWidth,
y1: 0,
x2: boundaryConfig.oneThirdWidth,
y2: configuration.svgHeight,
strokeWidth: 1
};
boundary[1] = {
x1: boundaryConfig.twoThirdsWidth,
y1: 0,
x2: boundaryConfig.twoThirdsWidth,
y2: configuration.svgHeight,
strokeWidth: 1
};
boundary[2] = {
x1: 0,
y1: boundaryConfig.oneThirdHeight,
x2: configuration.svgWidth,
y2: boundaryConfig.oneThirdHeight,
strokeWidth: 1
};
boundary[3] = {
x1: 0,
y1: boundaryConfig.twoThirdsHeight,
x2: configuration.svgWidth,
y2: boundaryConfig.twoThirdsHeight,
strokeWidth: 1
};
boundary[4] = {
x1: boundaryConfig.oneThirdWidth,
y1: boundaryConfig.oneThirdHeight,
x2: boundaryConfig.twoThirdsWidth,
y2: boundaryConfig.oneThirdHeight,
strokeWidth: 5
};
boundary[5] = {
x1: boundaryConfig.oneThirdWidth,
y1: boundaryConfig.twoThirdsHeight,
x2: boundaryConfig.twoThirdsWidth,
y2: boundaryConfig.twoThirdsHeight,
strokeWidth: 5
};
verticalBoundary[0] = {
x1: boundaryConfig.oneThirdWidth,
y1: boundaryConfig.oneThirdHeight,
x2: boundaryConfig.oneThirdWidth,
y2: boundaryConfig.twoThirdsHeight,
strokeWidth: 5
};
verticalBoundary[1] = {
x1: boundaryConfig.twoThirdsWidth,
y1: boundaryConfig.oneThirdHeight,
x2: boundaryConfig.twoThirdsWidth,
y2: boundaryConfig.twoThirdsHeight,
strokeWidth: 5
};

borderVisual
.data(border)
.attr("x1", d => {
return d.x1;
})
.attr("y1", d => {
return d.y1;
})
.attr("x2", d => {
return d.x2;
})
.attr("y2", d => {
return d.y2;
});
draggableHorizontalBorder
.data(horizontalBorder)
.attr("x1", d => {
return d.x1;
})
.attr("y1", d => {
return d.y1;
})
.attr("x2", d => {
return d.x2;
})
.attr("y2", d => {
return d.y2;
});
draggableVerticalBorder
.data(verticalBorder)
.attr("x1", d => {
return d.x1;
})
.attr("y1", d => {
return d.y1;
})
.attr("x2", d => {
return d.x2;
})
.attr("y2", d => {
return d.y2;
});
boundaryVisual
.data(boundary)
.lower()
.attr("x1", d => {
return d.x1;
})
.attr("y1", d => {
return d.y1;
})
.attr("x2", d => {
return d.x2;
})
.attr("y2", d => {
return d.y2;
});

draggableVerticalBoundary
.data(verticalBoundary)
.attr("x1", d => {
return d.x1;
})
.attr("y1", d => {
return d.y1;
})
.attr("x2", d => {
return d.x2;
})
.attr("y2", d => {
return d.y2;
});
if (d3cola != null && bEnableWrapping)
d3cola.updateConfiguration([
configuration.svgWidth,
configuration.svgHeight
]);
updateTorusLayout(
true,
graph,
twoEdgeWrappingGraph,
threeEdgeWrappingGraph,
boundaryConfig,
bEdgeWrappingConfig
);
})
.on('end', () => {
configuration.svgWidth +=
d3.event.x - draggableBorderConfig.dragStartX;
configuration.svgHeight = configuration.svgWidth;
draggableBorderConfig.dragStartX = d3.event.x;
draggableBorderConfig.dragStartY = d3.event.x;
border[0] = {
x1: 0,
y1: 0,
x2: configuration.svgWidth,
y2: 0,
strokeWidth: 1
};
border[1] = {
x1: 0,
y1: 0,
x2: 0,
y2: configuration.svgHeight,
strokeWidth: 1
};
horizontalBorder[0] = {
x1: 0,
y1: configuration.svgHeight,
x2: configuration.svgWidth,
y2: configuration.svgHeight,
strokeWidth: 1
};
verticalBorder[0] = {
x1: configuration.svgWidth,
y1: 0,
x2: configuration.svgWidth,
y2: configuration.svgHeight,
strokeWidth: 1
};
boundaryConfig.oneThirdWidth = configuration.svgWidth / 3;
boundaryConfig.twoThirdsWidth = (configuration.svgWidth * 2) / 3;
boundaryConfig.oneThirdHeight = configuration.svgHeight / 3;
boundaryConfig.twoThirdsHeight = (configuration.svgHeight * 2) / 3;

mutable centerSquareWidth = configuration.svgWidth;
mutable centerSquareHeight = configuration.svgHeight;
boundary[0] = {
x1: boundaryConfig.oneThirdWidth,
y1: 0,
x2: boundaryConfig.oneThirdWidth,
y2: configuration.svgHeight,
strokeWidth: 1
};
boundary[1] = {
x1: boundaryConfig.twoThirdsWidth,
y1: 0,
x2: boundaryConfig.twoThirdsWidth,
y2: configuration.svgHeight,
strokeWidth: 1
};
boundary[2] = {
x1: 0,
y1: boundaryConfig.oneThirdHeight,
x2: configuration.svgWidth,
y2: boundaryConfig.oneThirdHeight,
strokeWidth: 1
};
boundary[3] = {
x1: 0,
y1: boundaryConfig.twoThirdsHeight,
x2: configuration.svgWidth,
y2: boundaryConfig.twoThirdsHeight,
strokeWidth: 1
};
boundary[4] = {
x1: boundaryConfig.oneThirdWidth,
y1: boundaryConfig.oneThirdHeight,
x2: boundaryConfig.twoThirdsWidth,
y2: boundaryConfig.oneThirdHeight,
strokeWidth: 5
};
boundary[5] = {
x1: boundaryConfig.oneThirdWidth,
y1: boundaryConfig.twoThirdsHeight,
x2: boundaryConfig.twoThirdsWidth,
y2: boundaryConfig.twoThirdsHeight,
strokeWidth: 5
};
verticalBoundary[0] = {
x1: boundaryConfig.oneThirdWidth,
y1: boundaryConfig.oneThirdHeight,
x2: boundaryConfig.oneThirdWidth,
y2: boundaryConfig.twoThirdsHeight,
strokeWidth: 5
};
verticalBoundary[1] = {
x1: boundaryConfig.twoThirdsWidth,
y1: boundaryConfig.oneThirdHeight,
x2: boundaryConfig.twoThirdsWidth,
y2: boundaryConfig.twoThirdsHeight,
strokeWidth: 5
};

borderVisual
.data(border)
.attr("x1", d => {
return d.x1;
})
.attr("y1", d => {
return d.y1;
})
.attr("x2", d => {
return d.x2;
})
.attr("y2", d => {
return d.y2;
});
draggableHorizontalBorder
.data(horizontalBorder)
.attr("x1", d => {
return d.x1;
})
.attr("y1", d => {
return d.y1;
})
.attr("x2", d => {
return d.x2;
})
.attr("y2", d => {
return d.y2;
});
draggableVerticalBorder
.data(verticalBorder)
.attr("x1", d => {
return d.x1;
})
.attr("y1", d => {
return d.y1;
})
.attr("x2", d => {
return d.x2;
})
.attr("y2", d => {
return d.y2;
});
boundaryVisual
.data(boundary)
.lower()
.attr("x1", d => {
return d.x1;
})
.attr("y1", d => {
return d.y1;
})
.attr("x2", d => {
return d.x2;
})
.attr("y2", d => {
return d.y2;
});

draggableVerticalBoundary
.data(verticalBoundary)
.attr("x1", d => {
return d.x1;
})
.attr("y1", d => {
return d.y1;
})
.attr("x2", d => {
return d.x2;
})
.attr("y2", d => {
return d.y2;
});
if (d3cola != null && bEnableWrapping)
d3cola.updateConfiguration([
configuration.svgWidth,
configuration.svgHeight
]);
updateTorusLayout(
true,
graph,
twoEdgeWrappingGraph,
threeEdgeWrappingGraph,
boundaryConfig,
bEdgeWrappingConfig
);
})
);
return draggableVerticalBoundary;
}
Insert cell
boundaryVisual = {
let boundaryVisual = svgs
.selectAll(".bourndary")
.data(boundary)
.enter()
.append("line")
.attr("x1", d => {
return d.x1;
})
.attr("y1", d => {
return d.y1;
})
.attr("x2", d => {
return d.x2;
})
.attr("y2", d => {
return d.y2;
})
.lower()
.attr("class", "bourndary")
.style("stroke", "#BED7F6")
.style("stroke-width", d => {
return d.strokeWidth;
});
return boundaryVisual;
}
Insert cell
border = {
let border = new Array();
border.push({"x1":0, "y1":0, "x2":configuration.svgWidth, "y2":0, "strokeWidth":1});
border.push({"x1":0, "y1":0, "x2":0, "y2":configuration.svgHeight, "strokeWidth":1});
return border;
}
Insert cell
borderVisual = {
let borderVisual = svgs
.selectAll(".border")
.data(border)
.enter()
.append("line")
.attr("x1", d => {
return d.x1;
})
.attr("y1", d => {
return d.y1;
})
.attr("x2", d => {
return d.x2;
})
.attr("y2", d => {
return d.y2;
})
.attr("class", "border")
.style("stroke", "#BED7F6")
.style("stroke-width", d => {
return d.strokeWidth;
});
return borderVisual;
}
Insert cell
draggableHorizontalBorder = {
let draggableHorizontalBorder = svgs
.selectAll(".horizontal_border")
.data(horizontalBorder)
.enter()
.append("line")
.attr("x1", d => {
return d.x1;
})
.attr("y1", d => {
return d.y1;
})
.attr("x2", d => {
return d.x2;
})
.attr("y2", d => {
return d.y2;
})
.attr("class", "horizontal_border")
.style("stroke", "#BED7F6")
.style("stroke-width", d => {
return d.strokeWidth;
});

return draggableHorizontalBorder;
}
Insert cell
horizontalBorder = {
let horizontalBorder = new Array();
horizontalBorder.push({"x1":0, "y1":configuration.svgHeight, "x2":configuration.svgWidth, "y2":configuration.svgHeight, "strokeWidth":1});
return horizontalBorder;
}
Insert cell
draggableVerticalBorder = {
let draggableVerticalBorder = svgs
.selectAll(".vertical_border")
.data(verticalBorder)
.enter()
.append("line")
.attr("x1", d => {
return d.x1;
})
.attr("y1", d => {
return d.y1;
})
.attr("x2", d => {
return d.x2;
})
.attr("y2", d => {
return d.y2;
})
.attr("class", "vertical_border")
.style("stroke", "#BED7F6")
.style("stroke-width", d => {
return d.strokeWidth;
});

return draggableVerticalBorder;
}
Insert cell
verticalBorder = {
let verticalBorder = new Array();
verticalBorder.push({"x1":configuration.svgWidth, "y1":0, "x2":configuration.svgWidth, "y2":configuration.svgHeight, "strokeWidth":1});
return verticalBorder;
}
Insert cell
draggableBorderConfig = ({
"x": -15000,
"y": -15000,
"dragStartX":0,
"dragStartY": 0
})
Insert cell
twoEdgeWrappingGraph = ({
"nodes":[
],
"links":[
]
});
Insert cell
threeEdgeWrappingGraph = ({
"nodes":[
],
"links":[
]
})
Insert cell
svgs = d3.select(visual)
Insert cell
color = d3.scaleOrdinal(d3.schemeCategory10);
Insert cell
transformGroup = (graph, offsetX, offsetY) => {
for (let node of graph.nodes){
node.x += offsetX;
node.y += offsetY;
}
}
Insert cell
svgGroup = {
let svgGroup = svgs
.selectAll(".draggableGroup")
.data([{ x: 0, y: 0 }])
.enter()
.append("g")
.attr("class", "draggableGroup" + " cleanOnInit")
.attr("id", "parentGroup")
.attr("draggable", true)
.lower()
.on('touchstart', () => {
configuration.dragStartX = d3.event.touches[0].clientX;
configuration.dragStartY = d3.event.touches[0].clientY;
})
.on("touchmove", () => {
//apply transforma to graph
transformGroup(
graph,
d3.event.touches[0].clientX - configuration.dragStartX,
d3.event.touches[0].clientY - configuration.dragStartY
);

configuration.dragStartX = d3.event.touches[0].clientX;
configuration.dragStartY = d3.event.touches[0].clientY;

updateTorusLayout(
true,
graph,
twoEdgeWrappingGraph,
threeEdgeWrappingGraph,
boundaryConfig,
bEdgeWrappingConfig
);
})
// .on("touchend", () => {
// //apply transforma to graph
// transformGroup(
// graph,
// d3.event.touches[0].clientX - configuration.dragStartX,
// d3.event.touches[0].clientY - configuration.dragStartY
// );

// configuration.dragStartX = d3.event.touches[0].clientX;
// configuration.dragStartY = d3.event.touches[0].clientY;

// updateTorusLayout(
// true,
// graph,
// twoEdgeWrappingGraph,
// threeEdgeWrappingGraph,
// boundaryConfig,
// bEdgeWrappingConfig
// );
// })
.call(
d3
.drag()
.on('start', () => {
configuration.dragStartX = d3.event.x;
configuration.dragStartY = d3.event.y;
})
.on("drag", () => {
//apply transforma to graph
transformGroup(
graph,
d3.event.x - configuration.dragStartX,
d3.event.y - configuration.dragStartY
);

configuration.dragStartX = d3.event.x;
configuration.dragStartY = d3.event.y;

updateTorusLayout(
true,
graph,
twoEdgeWrappingGraph,
threeEdgeWrappingGraph,
boundaryConfig,
bEdgeWrappingConfig
);
})
.on("end", () => {
//apply transforma to graph
transformGroup(
graph,
d3.event.x - configuration.dragStartX,
d3.event.y - configuration.dragStartY
);

configuration.dragStartX = d3.event.x;
configuration.dragStartY = d3.event.y;

updateTorusLayout(
true,
graph,
twoEdgeWrappingGraph,
threeEdgeWrappingGraph,
boundaryConfig,
bEdgeWrappingConfig
);
})
);
return svgGroup;
}
Insert cell
rectangle = {
let rectangle = svgGroup
.selectAll(".background")
.data([{"x": 0, "y": 0}])
.enter()
.append("rect")
.attr("x", configuration.originX)
.attr("y", configuration.originY)
.attr("rx", 0)
.attr("ry", 0)
.attr("fill-opacity", 0)
.attr("width", configuration.width)
.attr("height", configuration.height)
.attr("class", "background" + " cleanOnInit")
.style("stroke", "black")
.style("fill", "white")
.lower();
return rectangle;
}
Insert cell
configuration = new Object({
originX: 0,
originY: 0,
dragStartX: 0,
dragStartY: 0,
width: 30000,
height: 30000,
svgWidth: 975,
svgHeight: 975
})
Insert cell
d3cola = cola
.d3adaptor(d3)
.linkDistance(120)
.avoidOverlaps(true)
.size([configuration.svgWidth, configuration.svgHeight])
.nodes(graph.nodes)
.links(graph.links)
.enableTorusWrapping(bEnableWrapping)
.on("tick", () => {
updateTorusLayout(
true,
graph,
twoEdgeWrappingGraph,
threeEdgeWrappingGraph,
boundaryConfig,
bEdgeWrappingConfig
);
})
.start()
Insert cell
initRender = {
for (let i in AreaClassCode) {
let areaClassName = AreaClassCode[i];

if (!bEnableWrapping || !bDisplayContext)
areaClassName = AreaClassCode._center.toString(); //draw only center square

let link = svgs
.selectAll(".link" + areaClassName)
.data(graph.links)
.enter()
.append("line")
.attr("class", "link" + areaClassName + " cleanOnInit")
.style("visibility", function(d) {
return "visible";
});

let nodeGroup = svgs
.selectAll(".draggableNodeGroup" + areaClassName)
.data(graph.nodes)
.enter()
.append("g")
.attr("class", "draggableNodeGroup" + areaClassName + " cleanOnInit")
.style("visibility", function(d) {
return d.visible == true ? "visible" : "hidden";
})
.attr("draggable", true)
.call(d3cola.drag);

let group = 7;
let node = nodeGroup
.append("circle")
.attr("class", "node" + areaClassName + " cleanOnInit")
.attr("r", 20)
.attr("cx", 0)
.attr("cy", 0)
.attr("stroke-width", "4px")
.attr("stroke", "black")
.style("fill", function(d) {
return color(d.id);
});

nodeGroup
.append("text")
.attr("class", "label" + areaClassName + " cleanOnInit")
.text(function(d) {
return d.name;
})
.attr("x", function(d) {
return d.relativeX;
})
.attr("y", function(d) {
var that = this;
return d.relativeY;
});

if (areaClassName != AreaClassCode._center) {
nodeGroup.style("opacity", 0.5);
link.style("opacity", 0.3);
}

if (!bEnableWrapping || !bDisplayContext) break;
}
}
Insert cell
function updateRender(shiftX, shiftY, areaClassName){
let nodeGroup = svgs.selectAll(".draggableNodeGroup" + areaClassName);
let link = svgs.selectAll(".link" + areaClassName);

//update
nodeGroup
.raise()
.attr("transform", function (d) {
return "translate("+ (d.x + shiftX) +","+ (d.y + shiftY)+")";
});

link.attr("x1", function (d) { return (d.source.x + shiftX); })
.attr("y1", function (d) { return (d.source.y + shiftY); })
.attr("x2", function (d) { return (d.target.x + shiftX); })
.attr("y2", function (d) { return (d.target.y + shiftY); })
.style("visibility", function (d) {
return d.visible == true ? "visible" : "hidden";
});
}
Insert cell
wrappingNode = (graph, boundaryConfig) => {
for (let node of graph.nodes) {
if (node.x > boundaryConfig.twoThirdsWidth) {
node.x -= boundaryConfig.oneThirdWidth;
while (node.x > boundaryConfig.twoThirdsWidth)
node.x -= boundaryConfig.oneThirdWidth;
} else if (node.x < boundaryConfig.oneThirdWidth) {
node.x += boundaryConfig.oneThirdWidth;
while (node.x < boundaryConfig.oneThirdWidth)
node.x += boundaryConfig.oneThirdWidth;
}

if (node.y > boundaryConfig.twoThirdsHeight) {
node.y -= boundaryConfig.oneThirdHeight;
while (node.y > boundaryConfig.twoThirdsHeight)
node.y -= boundaryConfig.oneThirdHeight;
} else if (node.y < boundaryConfig.oneThirdHeight) {
node.y += boundaryConfig.oneThirdHeight;
while (node.y < boundaryConfig.oneThirdHeight)
node.y += boundaryConfig.oneThirdHeight;
}
}
}
Insert cell
updateTorusLayout = (
bCheckWrapping,
graph,
twoEdgeWrappingGraph,
threeEdgeWrappingGraph,
boundaryConfig,
bEdgeWrappingConfig
) => {
if (bEdgeWrappingConfig != null && bEnableWrapping) {
computeTorusLayout(
graph,
twoEdgeWrappingGraph,
threeEdgeWrappingGraph,
bEdgeWrappingConfig,
boundaryConfig
);
wrappingNode(graph, boundaryConfig);
} else {
twoEdgeWrappingGraph.nodes.splice(0, twoEdgeWrappingGraph.nodes.length);
twoEdgeWrappingGraph.links.splice(0, twoEdgeWrappingGraph.links.length);
threeEdgeWrappingGraph.nodes.splice(0, threeEdgeWrappingGraph.nodes.length);
threeEdgeWrappingGraph.links.splice(0, threeEdgeWrappingGraph.links.length);
wrappingNodeLabel.splice(0, wrappingNodeLabel.length);
}

//center
updateRender(0, 0, AreaClassCode._center.toString());

if (bEnableWrapping && bDisplayContext) {
//left
updateRender(
-boundaryConfig.oneThirdWidth,
0,
AreaClassCode._left.toString()
);
//upper-left
updateRender(
-boundaryConfig.oneThirdWidth,
-boundaryConfig.oneThirdHeight,
AreaClassCode._upper_left.toString()
);
//top
updateRender(
0,
-boundaryConfig.oneThirdHeight,
AreaClassCode._top.toString()
);
//upper-right
updateRender(
boundaryConfig.oneThirdWidth,
-boundaryConfig.oneThirdHeight,
AreaClassCode._upper_right.toString()
);
//right
updateRender(
boundaryConfig.oneThirdWidth,
0,
AreaClassCode._right.toString()
);
//bottom-right
updateRender(
boundaryConfig.oneThirdWidth,
boundaryConfig.oneThirdHeight,
AreaClassCode._bottom_right.toString()
);
//bottom
updateRender(
0,
boundaryConfig.oneThirdHeight,
AreaClassCode._bottom.toString()
);
//bottom-left
updateRender(
-boundaryConfig.oneThirdWidth,
boundaryConfig.oneThirdHeight,
AreaClassCode._bottom_left.toString()
);
}

if (bEdgeWrappingConfig != null) {
//center
updateEdgeWrappingRender(
0,
0,
AreaClassCode._center.toString(),
twoEdgeWrappingGraph,
threeEdgeWrappingGraph
);

if (bEnableWrapping && bDisplayContext) {
//surrounding squares
//left
updateEdgeWrappingRender(
-boundaryConfig.oneThirdWidth,
0,
AreaClassCode._left.toString(),
twoEdgeWrappingGraph,
threeEdgeWrappingGraph
);

//upper-left
updateEdgeWrappingRender(
-boundaryConfig.oneThirdWidth,
-boundaryConfig.oneThirdHeight,
AreaClassCode._upper_left.toString(),
twoEdgeWrappingGraph,
threeEdgeWrappingGraph
);

//top
updateEdgeWrappingRender(
0,
-boundaryConfig.oneThirdHeight,
AreaClassCode._top.toString(),
twoEdgeWrappingGraph,
threeEdgeWrappingGraph
);

//upper-right
updateEdgeWrappingRender(
boundaryConfig.oneThirdWidth,
-boundaryConfig.oneThirdHeight,
AreaClassCode._upper_right.toString(),
twoEdgeWrappingGraph,
threeEdgeWrappingGraph
);

//right
updateEdgeWrappingRender(
boundaryConfig.oneThirdWidth,
0,
AreaClassCode._right.toString(),
twoEdgeWrappingGraph,
threeEdgeWrappingGraph
);

//bottom-right
updateEdgeWrappingRender(
boundaryConfig.oneThirdWidth,
boundaryConfig.oneThirdHeight,
AreaClassCode._bottom_right.toString(),
twoEdgeWrappingGraph,
threeEdgeWrappingGraph
);

//bottom
updateEdgeWrappingRender(
0,
boundaryConfig.oneThirdHeight,
AreaClassCode._bottom.toString(),
twoEdgeWrappingGraph,
threeEdgeWrappingGraph
);

//bottom-left
updateEdgeWrappingRender(
-boundaryConfig.oneThirdWidth,
boundaryConfig.oneThirdHeight,
AreaClassCode._bottom_left.toString(),
twoEdgeWrappingGraph,
threeEdgeWrappingGraph
);
}
}
}
Insert cell
updateEdgeWrappingRender = (
shiftX,
shiftY,
areaClassName,
twoEdgeWrappingGraph,
threeEdgeWrappingGraph
) => {
let twoEdgeWrappingNode = svgs
.selectAll(".twoEdgeWrappingNode" + areaClassName)
.data(twoEdgeWrappingGraph.nodes);

let twoEdgeWrappingNodeLabel = svgs
.selectAll(".wrappingNodeLabel" + areaClassName)
.data(wrappingNodeLabel);

let twoEdgeWrappingLink = svgs
.selectAll(".twoEdgeWrappingLink" + areaClassName)
.data(twoEdgeWrappingGraph.links);

//update
twoEdgeWrappingNode
.attr("cx", d => {
return d.x + shiftX;
})
.attr("cy", d => {
return d.y + shiftY;
})
.style("visibility", function(d) {
return d.visible == true ? "visible" : "hidden";
});

//enter
twoEdgeWrappingNode
.enter()
.append("circle")
.attr("class", "twoEdgeWrappingNode" + areaClassName + " cleanOnInit")
.attr("r", 4)
.attr("cx", d => {
return d.x + shiftX;
})
.attr("cy", d => {
return d.y + shiftY;
})
.attr("stroke", "black")
.style("fill", "#FFFFFF")
.style("visibility", function(d) {
return d.visible == true ? "visible" : "hidden";
});

//exit
twoEdgeWrappingNode.exit().remove();

if (bDisplayLabeledContext && areaClassName == AreaClassCode._center) {
//join
twoEdgeWrappingNodeLabel
.join("text")
.attr("class", "wrappingNodeLabel" + areaClassName + " cleanOnInit")
.attr("x", d => {
return 10 + d.x + shiftX;
})
.attr("y", d => {
return 10 + d.y + shiftY;
})
.text(d => {
if (d.name != undefined) return d.name;
})
.style("visibility", function(d) {
return d.visible == true ? "visible" : "hidden";
});
}

//update
twoEdgeWrappingLink
.attr("x1", function(d) {
return d.x1 + shiftX;
})
.attr("y1", function(d) {
return d.y1 + shiftY;
})
.attr("x2", function(d) {
return d.x2 + shiftX;
})
.attr("y2", function(d) {
return d.y2 + shiftY;
})
.lower()
.style("visibility", function(d) {
return d.visible == true ? "visible" : "hidden";
});

//enter
twoEdgeWrappingLink
.enter()
.append("line")
.attr("class", "twoEdgeWrappingLink" + areaClassName + " cleanOnInit")
.attr("x1", function(d) {
return d.x1 + shiftX;
})
.attr("y1", function(d) {
return d.y1 + shiftY;
})
.attr("x2", function(d) {
return d.x2 + shiftX;
})
.attr("y2", function(d) {
return d.y2 + shiftY;
})
.style("visibility", function(d) {
return d.visible == true ? "visible" : "hidden";
});

//exit
twoEdgeWrappingLink.exit().remove();

let threeEdgeWrappingNode = svgs
.selectAll(".threeEdgeWrappingNode" + areaClassName)
.data(threeEdgeWrappingGraph.nodes);

let threeEdgeWrappingLink = svgs
.selectAll(".threeEdgeWrappingLink" + areaClassName)
.data(threeEdgeWrappingGraph.links);

//update
threeEdgeWrappingNode
.attr("cx", d => {
return d.x + shiftX;
})
.attr("cy", d => {
return d.y + shiftY;
})
.style("visibility", function(d) {
return d.visible == true ? "visible" : "hidden";
});

//enter
threeEdgeWrappingNode
.enter()
.append("circle")
.attr("class", "threeEdgeWrappingNode" + areaClassName + " cleanOnInit")
.attr("r", 4)
.attr("cx", d => {
return d.x + shiftX;
})
.attr("cy", d => {
return d.y + shiftY;
})
.attr("stroke", "black")
.style("fill", "#FFFFFF")
.style("visibility", function(d) {
return d.visible == true ? "visible" : "hidden";
});

//exit
threeEdgeWrappingNode.exit().remove();

//update
threeEdgeWrappingLink
.attr("x1", function(d) {
return d.x1 + shiftX;
})
.attr("y1", function(d) {
return d.y1 + shiftY;
})
.attr("x2", function(d) {
return d.x2 + shiftX;
})
.attr("y2", function(d) {
return d.y2 + shiftY;
})
.style("visibility", function(d) {
return d.visible == true ? "visible" : "hidden";
});

//enter
threeEdgeWrappingLink
.enter()
.append("line")
.attr("class", "threeEdgeWrappingLink" + areaClassName + " cleanOnInit")
.attr("x1", function(d) {
return d.x1 + shiftX;
})
.attr("y1", function(d) {
return d.y1 + shiftY;
})
.attr("x2", function(d) {
return d.x2 + shiftX;
})
.attr("y2", function(d) {
return d.y2 + shiftY;
})
.style("visibility", function(d) {
return d.visible == true ? "visible" : "hidden";
});

//exit
threeEdgeWrappingLink.exit().remove();

if (areaClassName != AreaClassCode._center) {
twoEdgeWrappingNode.style("opacity", 0.3);
twoEdgeWrappingLink.style("opacity", 0.3);
threeEdgeWrappingNode.style("opacity", 0.3);
threeEdgeWrappingLink.style("opacity", 0.3);
}
}
Insert cell
AreaClassCode = ({
"_left" : 0,
"_upper_left" : 1,
"_top" : 2,
"_upper_right" : 3,
"_right" : 4,
"_bottom_left" : 5,
"_bottom" : 6,
"_bottom_right" : 7,
"_center" : 8
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
d3 = require("d3@5")
Insert cell
cola = require("https://ialab.it.monash.edu/~kche0088/WebCola/cola.min.js")
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more