From c16b2a3c580873fa75f9bbaf821b43fc25c0c2b2 Mon Sep 17 00:00:00 2001 From: wimrijnders Date: Tue, 13 Jun 2017 20:46:08 +0200 Subject: [PATCH] Network: Smooth type 'dynamic' adjusted for node-specific option in hierarchical (#3130) Fix for #3036 Option `smooth.type: dynamic` is not allowed for hierarchical layouts. This was handled properly for the main options, but not for the node-specific options. Options within node instances arei now checked for `smooth.type: dynamic` and replaced by `horizontal` or `vertical`. The implementation adds listener `_adjustEdgesForHierarchicalLayout` in `LayoutHandler`. This listener must be activated every time noder- specific options might change. This happens in the logical places within `EdgeHandler`. --- lib/network/modules/EdgesHandler.js | 20 ++++++++++++---- lib/network/modules/LayoutEngine.js | 36 ++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/lib/network/modules/EdgesHandler.js b/lib/network/modules/EdgesHandler.js index d62ba685..81841525 100644 --- a/lib/network/modules/EdgesHandler.js +++ b/lib/network/modules/EdgesHandler.js @@ -4,6 +4,7 @@ var DataView = require('../../DataView'); var Edge = require("./components/Edge").default; var Label = require("./components/shared/Label").default; +var LayoutEngine = require("./LayoutEngine").default; // For access to LayoutEngine.getStaticType() class EdgesHandler { constructor(body, images, groups) { @@ -115,11 +116,11 @@ class EdgesHandler { bindEventListeners() { // this allows external modules to force all dynamic curves to turn static. - this.body.emitter.on("_forceDisableDynamicCurves", (type) => { + this.body.emitter.on("_forceDisableDynamicCurves", (type, emit = true) => { if (type === 'dynamic') { type = 'continuous'; } - let emitChange = false; + let dataChanged = false; for (let edgeId in this.body.edges) { if (this.body.edges.hasOwnProperty(edgeId)) { let edge = this.body.edges[edgeId]; @@ -137,18 +138,25 @@ class EdgesHandler { else { edge.setOptions({smooth: {type: type}}); } - emitChange = true; + dataChanged = true; } } } } } - if (emitChange === true) { + if (emit === true && dataChanged === true) { this.body.emitter.emit("_dataChanged"); } }); // this is called when options of EXISTING nodes or edges have changed. + // + // NOTE: Not true, called when options have NOT changed, for both existing as well as new nodes. + // See update() for logic. + // TODO: Verify and examine the consequences of this. It might still trigger when + // non-option fields have changed, but then reconnecting edges is still useless. + // Alternatively, it might also be called when edges are removed. + // this.body.emitter.on("_dataUpdated", () => { this.reconnectEdges(); }); @@ -247,6 +255,7 @@ class EdgesHandler { this.add(ids, true); } + this.body.emitter.emit('_adjustEdgesForHierarchicalLayout'); if (doNotEmit === false) { this.body.emitter.emit("_dataChanged"); } @@ -274,6 +283,8 @@ class EdgesHandler { edges[id] = this.create(data); } + this.body.emitter.emit('_adjustEdgesForHierarchicalLayout'); + if (doNotEmit === false) { this.body.emitter.emit("_dataChanged"); } @@ -308,6 +319,7 @@ class EdgesHandler { } if (dataChanged === true) { + this.body.emitter.emit('_adjustEdgesForHierarchicalLayout'); this.body.emitter.emit("_dataChanged"); } else { diff --git a/lib/network/modules/LayoutEngine.js b/lib/network/modules/LayoutEngine.js index 0f5ee88f..1c54d34f 100644 --- a/lib/network/modules/LayoutEngine.js +++ b/lib/network/modules/LayoutEngine.js @@ -207,6 +207,16 @@ class LayoutEngine { this.body.emitter.on('_resetHierarchicalLayout', () => { this.setupHierarchicalLayout(); }); + this.body.emitter.on('_adjustEdgesForHierarchicalLayout', () => { + if (this.options.hierarchical.enabled !== true) { + return; + } + // get the type of static smooth curve in case it is required + let type = this.getStaticType(); + + // force all edges into static smooth curves. + this.body.emitter.emit('_forceDisableDynamicCurves', type, false); + }); } setOptions(options, allOptions) { @@ -275,11 +285,7 @@ class LayoutEngine { } // get the type of static smooth curve in case it is required - // NOTE: 'type' here is for the curve, so it will be orthogonal to the network direction - let type = 'horizontal'; - if (!this._isVertical()) { - type = 'vertical'; // sic - } + let type = this.getStaticType(); // disable smooth curves if nothing is defined. If smooth curves have been turned on, // turn them into static smooth curves. @@ -324,7 +330,7 @@ class LayoutEngine { } // Force all edges into static smooth curves. - //Only applies to edges that do not use the global options for smooth. + // Only applies to edges that do not use the global options for smooth. this.body.emitter.emit('_forceDisableDynamicCurves', type); } @@ -1559,6 +1565,24 @@ class LayoutEngine { } + /** + * Get the type of static smooth curve in case it is required. + * + * The return value is the type to use to translate dynamic curves to + * another type, in the case of hierarchical layout. Dynamic curves do + * not work for that layout type. + */ + getStaticType() { + // Node that 'type' is the edge type, and therefore 'orthogonal' to the layout type. + let type = 'horizontal'; + if (!this._isVertical()) { + type = 'vertical'; + } + + return type; + } + + /** * Determine the center position of a branch from the passed list of child nodes *