Skip to content
This repository has been archived by the owner on Jul 29, 2019. It is now read-only.

Added option layout.hierarchical.userControlsFreeAxis (revision 2) #4183

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 117 additions & 1 deletion examples/network/other/manipulation.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,97 @@
// randomly create some nodes and edges
var data = getScaleFreeNetwork(25);
var seed = 2;

function bakeLevels() {
let direction = network.layoutEngine.options.hierarchical.direction;
console.log(direction);
let levelAxis = "";

//
// direction can only be "UD" | "DU" | "LR" | "RL", other values are caught as errors earlier in the program
// once levels are baked, they should not change even if the user alters the direction of the layout
//

if (direction == "UD" || direction == "DU") {
levelAxis = "y";
}
else {
levelAxis = "x";
}

let nodes = network.body.nodes;
let nodeIds = Object.getOwnPropertyNames(nodes);
let nodeLevelMap = new Map();
let uniqueLevelsInCanvasSpace = new Set();

for (nodeId of nodeIds) {
node = nodes[nodeId];
uniqueLevelsInCanvasSpace.add(node[levelAxis]);
if (nodeLevelMap.has(node[levelAxis])) {
nodeLevelMap.get(node[levelAxis]).push(node.id);
}
else {
nodeLevelMap.set(node[levelAxis], [node.id]);
}
}

orderedUniqueLevelsInCanvasSpace = Array.from(uniqueLevelsInCanvasSpace);
orderedUniqueLevelsInCanvasSpace.sort((a,b) => { return a-b; });
canvasLevelMap = new Map();

for (let i = 0; i < orderedUniqueLevelsInCanvasSpace.length; i++) {
canvasLevelMap.set(orderedUniqueLevelsInCanvasSpace[i], i);
}

updateList = []

for (nodeId of nodeIds) {
node = nodes[nodeId];
updateList.push({
"id": nodeId,
"level": canvasLevelMap.get(node[levelAxis])
});
}

console.log(network);
network.body.data.nodes.update(updateList);

}

function storeFreeAxisPositions() {
let direction = network.layoutEngine.options.hierarchical.direction;
let freeAxis = "";

if (direction == "UD" || direction == "DU") {
freeAxis = "x";
}
else {
freeAxis = "y";
}

let positions = network.getPositions();
let keys = Object.getOwnPropertyNames(positions);
let updateList = [];
for (key of keys) {
pos = positions[key];
updateList.push({
id: key,
[freeAxis]: pos[freeAxis]
});
}
network.body.data.nodes.update(updateList);
}

function toggleBakeLevelsButton() {
let target = document.getElementById("bake-levels");
let isDisabled = target.hasAttribute("disabled");
if (isDisabled) {
target.removeAttribute("disabled");
}
else {
target.setAttribute("disabled", "")
}
}

function setDefaultLocale() {
var defaultLocal = navigator.language;
Expand Down Expand Up @@ -92,7 +183,10 @@
// create a network
var container = document.getElementById('mynetwork');
var options = {
layout: {randomSeed:seed}, // just to make sure the layout is the same when the locale is changed
configure: true,
layout: {
randomSeed:seed
}, // just to make sure the layout is the same when the locale is changed
locale: document.getElementById('locale').value,
manipulation: {
addNode: function (data, callback) {
Expand Down Expand Up @@ -127,6 +221,21 @@
}
};
network = new vis.Network(container, data, options);
network.on("configChange", (e) => {
if (e.layout) {
if (e.layout.hierarchical) {
if (e.layout.hierarchical === true) {
toggleBakeLevelsButton();
}
if (e.layout.hierarchical.enabled === false) {
toggleBakeLevelsButton();
}
}
}
});
network.on("dragEnd", (e) => {
storeFreeAxisPositions();
});
}

function clearPopUp() {
Expand Down Expand Up @@ -187,6 +296,13 @@ <h2>Editing the nodes and edges (localized)</h2>
<input type="button" value="cancel" id="cancelButton" />
</div>
<br />
<input disabled type="button" id="bake-levels" value="Bake hierarchical levels" onClick="bakeLevels()"
title="
+ This will permanently set the levels assigned to each node by Vis.js' built-in hierarchical layout algorithm.
+ This button is active when both 'layout.hierarchical' and its sub-option 'layout.hierarchical.userControlsFreeAxis' are enabled.
+ In a realworld use-case, the programmer will probably manually set each node's levels according to their own algorithm.
+ 'userControlsFreeAxis' is best used with physics disabled.
+ It is not recommended to swap between directions when the user is in control of the free axis." >
<div id="mynetwork"></div>

</body>
Expand Down
15 changes: 15 additions & 0 deletions lib/network/Network.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,21 @@ Network.prototype.setOptions = function (options) {

// the hierarchical system can adapt the edges and the physics to it's own options because not all combinations work with the hierarichical system.
options = this.layoutEngine.setOptions(options.layout, options);
console.log(this.layoutEngine);
//
// this clears "userControlsFreeAxis" when "hierarchical" is disabled
// without doing this, and performing the following steps:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May still be a good idea to clear the userControlsFreeAxis option if hierarchical layout is disabled, but the bug I was attempting to fix is probably #4228.

// enable layout.hierarchical
// enable layout.userControlsFreeAxis
// disable layout.hierarchical
// enable layout.hierarchical
// edges were getting placed into the body.nodes in LayoutEngine::setupHierarchicalLayout
//
// is there a better way to perform this, or better place to put this? It feels like a hack.
//
if (this.layoutEngine.options.hierarchical.enabled == false) {
this.layoutEngine.options.hierarchical["userControlsFreeAxis"] = false;
}

this.canvas.setOptions(options); // options for canvas are in globals

Expand Down
17 changes: 11 additions & 6 deletions lib/network/modules/LayoutEngine.js
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,6 @@ class LayoutEngine {
// capture them now
//
let nodeIds = [];

// fallback for cases where there are nodes but no edges
for (let nodeId in this.body.nodes) {
if (this.body.nodes.hasOwnProperty(nodeId)) {
Expand Down Expand Up @@ -785,17 +784,23 @@ class LayoutEngine {
let direction = this.options.hierarchical.direction;
let dataSet = this.body.data.nodes.getDataSet();
let freeAxis = "";
if (direction === "UD" || direction === "DU") {

if (direction === "UD" || direction === "DU") {
freeAxis = "x";
}
else { // direction === "LR" || direction == "RL", any other values are caught as errors earlier in the program
else { // direction == "LR" || direction == "RL", any other values are caught as errors earlier in the program
freeAxis = "y";
}
for (let nodeId of nodeIds) {

for (let nodeId of nodeIds) {
console.log(nodeId);
let targetPosition = dataSet._data[nodeId][freeAxis];
if (targetPosition !== undefined) {
this.body.nodes[nodeId][freeAxis] = targetPosition;
}
this.body.nodes[nodeId][freeAxis] = targetPosition;
}
else { // explicitly assign it the freeaxis value as issued by layout engine
dataSet._data[nodeId][freeAxis] = this.body.nodes[nodeId][freeAxis]
}
}
}

Expand Down