Skip to content
This repository was archived by the owner on Jul 29, 2019. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5aa761c
The next fix on Travis unit test failure
axizo-pi Sep 10, 2017
ab58653
Preliminary refactoring in utils.js
axizo-pi Sep 10, 2017
a4d37db
Merged with develop
axizo-pi Sep 10, 2017
4ef764c
Merge with 'develop'
axizo-pi Sep 10, 2017
d3eb615
Added unit tests for extend routines, commenting and small fixes
axizo-pi Sep 11, 2017
51a517d
More unit tests for extend routines
axizo-pi Sep 11, 2017
fbdbc3d
- Completed unit tests for extend routines in
axizo-pi Sep 12, 2017
990c899
Added unit tests for known font options
axizo-pi Sep 12, 2017
3b2532d
Fixed conflicts
axizo-pi Sep 14, 2017
4860af5
Interim save before trying out another proto chain strategy
axizo-pi Sep 14, 2017
a26643a
Fixed problem in first example #3408
axizo-pi Sep 14, 2017
2559e82
Removed silly file that shouldn't be there
axizo-pi Sep 14, 2017
79ca391
Added unit test for multi-fonts
axizo-pi Sep 14, 2017
305a8a7
Comment edits
axizo-pi Sep 14, 2017
bb095d3
Verufy unit tests, small adjustments for groups
axizo-pi Sep 15, 2017
fd662ed
merged with develop, fixed conflicts
axizo-pi Sep 16, 2017
b64beaf
Merge branch 'develop' into refactorExtendRoutines
axizo-pi Sep 16, 2017
5a9006c
Merge branch 'refactorExtendRoutines' into fix_modFonts
axizo-pi Sep 16, 2017
522928c
Further work on getting unit tests to work. PARTS NEED TO BE CLEANED UP!
axizo-pi Sep 17, 2017
c8c2f59
Merge branch 'develop' into fix_modFonts
axizo-pi Sep 17, 2017
3b3af16
Further tweaks to get unit tests working
axizo-pi Sep 18, 2017
9cf0ec0
All unit tests passing
axizo-pi Sep 24, 2017
3c33056
Fixes due to linting
axizo-pi Sep 24, 2017
33b081a
Small edits
axizo-pi Sep 24, 2017
2ffe6e8
Merged and fixed conflicts
axizo-pi Sep 24, 2017
6547a9c
Removed prototype handling from font pile
axizo-pi Sep 24, 2017
770044c
Fixes during testing examples of #3408
axizo-pi Sep 24, 2017
9b35a36
Added unit test for edge labels, small fixes
axizo-pi Sep 24, 2017
1224cb8
Added unit tests for shorthand string fonts; some tests still failing
axizo-pi Sep 25, 2017
230f663
All unit tests pass
axizo-pi Sep 26, 2017
24214c4
Removed Label.parseOptions()
axizo-pi Sep 26, 2017
dff9037
Completed shorthand font tests, code cleanup, fixed choosify for edges
axizo-pi Sep 26, 2017
f2e9521
Addressed review comments
axizo-pi Sep 26, 2017
a331a18
Merge branch 'develop' into fix_modFonts
axizo-pi Sep 26, 2017
9da8d47
Addressed review comments, cleanup
axizo-pi Sep 27, 2017
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
19 changes: 2 additions & 17 deletions lib/network/modules/EdgesHandler.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
var util = require("../../util");
var DataSet = require('../../DataSet');
var DataView = require('../../DataView');

var Edge = require("./components/Edge").default;
var Label = require("./components/shared/Label").default;

/**
* Handler for Edges
Expand Down Expand Up @@ -31,7 +29,7 @@ class EdgesHandler {
this.options = {};
this.defaultOptions = {
arrows: {
to: {enabled: false, scaleFactor:1, type: 'arrow'}, // boolean / {arrowScaleFactor:1} / {enabled: false, arrowScaleFactor:1}
to: {enabled: false, scaleFactor:1, type: 'arrow'},// boolean / {arrowScaleFactor:1} / {enabled: false, arrowScaleFactor:1}
middle: {enabled: false, scaleFactor:1, type: 'arrow'},
from: {enabled: false, scaleFactor:1, type: 'arrow'}
},
Expand Down Expand Up @@ -193,7 +191,6 @@ class EdgesHandler {
* @param {Object} options
*/
setOptions(options) {
this.edgeOptions = options;
if (options !== undefined) {
// use the parser from the Edge class to fill in all shorthand notations
Edge.parseOptions(this.options, options, true, this.defaultOptions, true);
Expand All @@ -210,8 +207,6 @@ class EdgesHandler {

// update fonts in all edges
if (options.font !== undefined) {
// use the parser from the Label class to fill in all shorthand notations
Label.parseOptions(this.options.font, options);
for (let edgeId in this.body.edges) {
if (this.body.edges.hasOwnProperty(edgeId)) {
this.body.edges[edgeId].updateLabelModule();
Expand Down Expand Up @@ -383,17 +378,7 @@ class EdgesHandler {
* @returns {Edge}
*/
create(properties) {
// It is not at all clear why all these separate options should be passed:
//
// - this.edgeOptions is set in setOptions()
// the value of which is also added to this.options with parseOptions()
// - this.defaultOptions has been added to this.options with util.extend() in ctor
//
// So, in theory, this.options should be enough.
// The only reason I can think of for this, is that precedence is important.
// TODO: make unit tests for this, to check if edgeOptions and defaultOptions are redundant
//
return new Edge(properties, this.body, this.options, this.defaultOptions, this.edgeOptions)
return new Edge(properties, this.body, this.options, this.defaultOptions)
}

/**
Expand Down
15 changes: 9 additions & 6 deletions lib/network/modules/Groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,17 @@ class Groups {
}

/**
* get group options of a groupname. If groupname is not found, a new group
* is added.
* @param {*} groupname Can be a number, string, Date, etc.
* @return {Object} group The created group, containing all group options
* Get group options of a groupname.
* If groupname is not found, a new group may be created.
*
* @param {*} groupname Can be a number, string, Date, etc.
* @param {boolean} [shouldCreate=true] If true, create a new group
* @return {Object} The found or created group
*/
get(groupname) {
get(groupname, shouldCreate = true) {
let group = this.groups[groupname];
if (group === undefined) {

if (group === undefined && shouldCreate) {
if (this.options.useDefaultGroups === false && this.groupsArray.length > 0) {
// create new group
let index = this.groupIndex % this.groupsArray.length;
Expand Down
10 changes: 3 additions & 7 deletions lib/network/modules/NodesHandler.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
let util = require("../../util");
let DataSet = require('../../DataSet');
let DataView = require('../../DataView');

var Node = require("./components/Node").default;
var Label = require("./components/shared/Label").default;

Copy link
Member

Choose a reason for hiding this comment

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

extra line

Copy link
Author

Choose a reason for hiding this comment

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

You mean that there are two empty lines? I actually prefer this, for better visual separation. I do it between methods as well, and in other places where I think a bigger distinction between blocks is useful.


/**
* Handler for Nodes
Expand All @@ -30,7 +29,6 @@ class NodesHandler {
remove: (event, params) => { this.remove(params.items); }
};

this.options = {};
this.defaultOptions = {
borderWidth: 1,
borderWidthSelected: 2,
Expand Down Expand Up @@ -144,7 +142,7 @@ class NodesHandler {
throw 'Internal error: mass in defaultOptions of NodesHandler may not be zero or negative';
}

util.extend(this.options, this.defaultOptions);
this.options = util.bridgeObject(this.defaultOptions);

this.bindEventListeners();
}
Expand Down Expand Up @@ -174,7 +172,6 @@ class NodesHandler {
* @param {Object} options
*/
setOptions(options) {
this.nodeOptions = options;
if (options !== undefined) {
Node.parseOptions(this.options, options);

Expand All @@ -189,7 +186,6 @@ class NodesHandler {

// update the font in all nodes
if (options.font !== undefined) {
Label.parseOptions(this.options.font, options);
for (let nodeId in this.body.nodes) {
if (this.body.nodes.hasOwnProperty(nodeId)) {
this.body.nodes[nodeId].updateLabelModule();
Expand Down Expand Up @@ -359,7 +355,7 @@ class NodesHandler {
* @returns {*}
*/
create(properties, constructorClass = Node) {
return new constructorClass(properties, this.body, this.images, this.groups, this.options, this.defaultOptions, this.nodeOptions)
return new constructorClass(properties, this.body, this.images, this.groups, this.options, this.defaultOptions)
}


Expand Down
26 changes: 13 additions & 13 deletions lib/network/modules/components/Edge.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,18 @@ class Edge {
* @param {Object} body shared state from Network instance
* @param {Object} globalOptions options from the EdgesHandler instance
* @param {Object} defaultOptions default options from the EdgeHandler instance. Value and reference are constant
* @param {Object} edgeOptions option values specific for edges.
*/
constructor(options, body, globalOptions, defaultOptions, edgeOptions) {
constructor(options, body, globalOptions, defaultOptions) {
if (body === undefined) {
throw new Error("No body provided");
}

// Since globalOptions is constant in values as well as reference,
// Following needs to be done only once.


this.options = util.bridgeObject(globalOptions);
this.globalOptions = globalOptions;
this.defaultOptions = defaultOptions;
this.edgeOptions = edgeOptions;
this.body = body;

// initialize variables
Expand Down Expand Up @@ -84,12 +81,11 @@ class Edge {
options.value = parseFloat(options.value);
}

let pile = [options, this.options, this.edgeOptions, this.defaultOptions];
let pile = [options, this.options, this.defaultOptions];
this.chooser = ComponentUtil.choosify('edge', pile);

// update label Module
this.updateLabelModule(options);
this.labelModule.propagateFonts(this.edgeOptions, options, this.defaultOptions);

let dataChanged = this.updateEdgeType();

Expand Down Expand Up @@ -134,7 +130,9 @@ class Edge {
'to',
'title',
'value',
'width'
'width',
'font',
'chosen'
];

// only deep extend the items in the field array. These do not have shorthand.
Expand Down Expand Up @@ -228,11 +226,7 @@ class Edge {
parentOptions.color = util.bridgeObject(globalOptions.color); // set the object back to the global options
}

// handle the font settings
if (newOptions.font !== undefined && newOptions.font !== null) {
Label.parseOptions(parentOptions.font, newOptions);
}
else if (allowDeletion === true && newOptions.font === null) {
if (allowDeletion === true && newOptions.font === null) {
parentOptions.font = util.bridgeObject(globalOptions.font); // set the object back to the global options
}
}
Expand Down Expand Up @@ -321,7 +315,13 @@ class Edge {
* @param {Object} options
*/
updateLabelModule(options) {
let pile = [options, this.edgeOptions, this.defaultOptions];
let pile = [
options,
this.options,
this.globalOptions, // Currently set global edge options
this.defaultOptions
];

this.labelModule.update(this.options, pile);

if (this.labelModule.baseSize !== undefined) {
Expand Down
110 changes: 75 additions & 35 deletions lib/network/modules/components/Node.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,29 +32,22 @@ class Node {
* {string} label Text label for the node
* {number} x Horizontal position of the node
* {number} y Vertical position of the node
* {string} shape Node shape, available:
* "database", "circle", "ellipse",
* "box", "image", "text", "dot",
* "star", "triangle", "triangleDown",
* "square", "icon"
* {string} shape Node shape
* {string} image An image url
* {string} title An title text, can be HTML
* {string} title A title text, can be HTML
* {anytype} group A group name or number
* @param {Object} body
* @param {Network.Images} imagelist A list with images. Only needed
* when the node has an image
* @param {Groups} grouplist A list with groups. Needed for
* retrieving group options
* @param {Object} globalOptions An object with default values for
* example for the color
* @param {Object} defaultOptions
* @param {Object} nodeOptions
*
* @param {Object} body Shared state of current network instance
* @param {Network.Images} imagelist A list with images. Only needed when the node has an image
* @param {Groups} grouplist A list with groups. Needed for retrieving group options
* @param {Object} globalOptions Current global node options; these serve as defaults for the node instance
* @param {Object} defaultOptions Global default options for nodes; note that this is also the prototype
* for parameter `globalOptions`.
*/
constructor(options, body, imagelist, grouplist, globalOptions, defaultOptions, nodeOptions) {
constructor(options, body, imagelist, grouplist, globalOptions, defaultOptions) {
this.options = util.bridgeObject(globalOptions);
this.globalOptions = globalOptions;
this.defaultOptions = defaultOptions;
this.nodeOptions = nodeOptions;
this.body = body;

this.edges = []; // all edges connected to this node
Expand Down Expand Up @@ -136,24 +129,15 @@ class Node {
if (options.size !== undefined) {this.baseSize = options.size;}
if (options.value !== undefined) {options.value = parseFloat(options.value);}

// copy group options
if (typeof options.group === 'number' || (typeof options.group === 'string' && options.group != '')) {
var groupObj = this.grouplist.get(options.group);
util.deepExtend(this.options, groupObj);
// the color object needs to be completely defined. Since groups can partially overwrite the colors, we parse it again, just in case.
this.options.color = util.parseColor(this.options.color);
}

// this transforms all shorthands into fully defined options
Node.parseOptions(this.options, options, true, this.globalOptions);
Node.parseOptions(this.options, options, true, this.globalOptions, this.grouplist);

let pile = [options, this.options, this.defaultOptions];
this.chooser = ComponentUtil.choosify('node', pile);

this._load_images();
this.updateLabelModule(options);
this.updateShape(currentShape);
this.labelModule.propagateFonts(this.nodeOptions, options, this.defaultOptions);

return (options.hidden !== undefined || options.physics !== undefined);
}
Expand Down Expand Up @@ -199,6 +183,43 @@ class Node {
}


/**
* Copy group option values into the node options.
*
* The group options override the global node options, so the copy of group options
* must happen *after* the global node options have been set.
*
* This method must also be called also if the global node options have changed and the group options did not.
*
* @param {Object} parentOptions
* @param {Object} newOptions new values for the options, currently only passed in for check
* @param {Object} groupList
*/
static updateGroupOptions(parentOptions, newOptions, groupList) {
if (groupList === undefined) return; // No groups, nothing to do

var group = parentOptions.group;

// paranoia: the selected group is already merged into node options, check.
if (newOptions !== undefined && newOptions.group !== undefined && group !== newOptions.group) {
throw new Error("updateGroupOptions: group values in options don't match.");
}

var hasGroup = (typeof group === 'number' || (typeof group === 'string' && group != ''));
if (!hasGroup) return; // current node has no group, no need to merge

var groupObj = groupList.get(group);

// Skip merging of group font options into parent; these are required to be distinct for labels
// TODO: It might not be a good idea either to merge the rest of the options, investigate this.
util.selectiveNotDeepExtend(['font'], parentOptions, groupObj);

// the color object needs to be completely defined.
// Since groups can partially overwrite the colors, we parse it again, just in case.
parentOptions.color = util.parseColor(parentOptions.color);
}


/**
* This process all possible shorthands in the new options and makes sure that the parentOptions are fully defined.
* Static so it can also be used by the handler.
Expand All @@ -207,12 +228,13 @@ class Node {
* @param {Object} newOptions
* @param {boolean} [allowDeletion=false]
* @param {Object} [globalOptions={}]
* @param {Object} [groupList]
* @static
*/
static parseOptions(parentOptions, newOptions, allowDeletion = false, globalOptions = {}) {
static parseOptions(parentOptions, newOptions, allowDeletion = false, globalOptions = {}, groupList) {

var fields = [
'color',
'font',
'fixed',
'shadow'
];
Expand Down Expand Up @@ -248,14 +270,12 @@ class Node {
}
}

// handle the font options
if (newOptions.font !== undefined && newOptions.font !== null) {
Label.parseOptions(parentOptions.font, newOptions);
}
else if (allowDeletion === true && newOptions.font === null) {
if (allowDeletion === true && newOptions.font === null) {
parentOptions.font = util.bridgeObject(globalOptions.font); // set the object back to the global options
}

Node.updateGroupOptions(parentOptions, newOptions, groupList);

// handle the scaling options, specifically the label part
if (newOptions.scaling !== undefined) {
util.mergeOptions(parentOptions.scaling, newOptions.scaling, 'label', globalOptions.scaling);
Expand Down Expand Up @@ -319,7 +339,27 @@ class Node {
if (this.options.label === undefined || this.options.label === null) {
this.options.label = '';
}
let pile = [options, this.nodeOptions, this.defaultOptions];

Node.updateGroupOptions(this.options, options, this.grouplist);

//
// Note:The prototype chain for this.options is:
//
// this.options -> NodesHandler.options -> NodesHandler.defaultOptions
// (also: this.globalOptions)
//
// Note that the prototypes are mentioned explicitly in the pile list below;
// WE DON'T WANT THE ORDER OF THE PROTOTYPES!!!! At least, not for font handling of labels.
// This is a good indication that the prototype usage of options is deficient.
//
var currentGroup = this.grouplist.get(this.options.group, false);
let pile = [
options, // new options
this.options, // current node options, see comment above for prototype
currentGroup, // group options, if any
this.globalOptions, // Currently set global node options
this.defaultOptions // Default global node options
];
this.labelModule.update(this.options, pile);

if (this.labelModule.baseSize !== undefined) {
Expand Down
5 changes: 3 additions & 2 deletions lib/network/modules/components/nodes/Cluster.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ class Cluster extends Node {
* @param {Array.<HTMLImageElement>}imagelist
* @param {Array} grouplist
* @param {Object} globalOptions
* @param {Object} defaultOptions Global default options for nodes
*/
constructor(options, body, imagelist, grouplist, globalOptions) {
super(options, body, imagelist, grouplist, globalOptions);
constructor(options, body, imagelist, grouplist, globalOptions, defaultOptions) {
super(options, body, imagelist, grouplist, globalOptions, defaultOptions);

this.isCluster = true;
this.containedNodes = {};
Expand Down
Loading