179 lines
6.5 KiB
JavaScript
179 lines
6.5 KiB
JavaScript
/* *
|
|
*
|
|
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
|
|
*
|
|
* */
|
|
import H from '../parts/Globals.js';
|
|
import Point from '../parts/Point.js';
|
|
import U from '../parts/Utilities.js';
|
|
var defined = U.defined, extend = U.extend, find = U.find, pick = U.pick;
|
|
H.NodesMixin = {
|
|
/* eslint-disable valid-jsdoc */
|
|
/**
|
|
* Create a single node that holds information on incoming and outgoing
|
|
* links.
|
|
* @private
|
|
*/
|
|
createNode: function (id) {
|
|
/**
|
|
* @private
|
|
*/
|
|
function findById(nodes, id) {
|
|
return find(nodes, function (node) {
|
|
return node.id === id;
|
|
});
|
|
}
|
|
var node = findById(this.nodes, id), PointClass = this.pointClass, options;
|
|
if (!node) {
|
|
options = this.options.nodes && findById(this.options.nodes, id);
|
|
node = (new PointClass()).init(this, extend({
|
|
className: 'highcharts-node',
|
|
isNode: true,
|
|
id: id,
|
|
y: 1 // Pass isNull test
|
|
}, options));
|
|
node.linksTo = [];
|
|
node.linksFrom = [];
|
|
node.formatPrefix = 'node';
|
|
node.name = node.name || node.options.id; // for use in formats
|
|
// Mass is used in networkgraph:
|
|
node.mass = pick(
|
|
// Node:
|
|
node.options.mass, node.options.marker && node.options.marker.radius,
|
|
// Series:
|
|
this.options.marker && this.options.marker.radius,
|
|
// Default:
|
|
4);
|
|
/**
|
|
* Return the largest sum of either the incoming or outgoing links.
|
|
* @private
|
|
*/
|
|
node.getSum = function () {
|
|
var sumTo = 0, sumFrom = 0;
|
|
node.linksTo.forEach(function (link) {
|
|
sumTo += link.weight;
|
|
});
|
|
node.linksFrom.forEach(function (link) {
|
|
sumFrom += link.weight;
|
|
});
|
|
return Math.max(sumTo, sumFrom);
|
|
};
|
|
/**
|
|
* Get the offset in weight values of a point/link.
|
|
* @private
|
|
*/
|
|
node.offset = function (point, coll) {
|
|
var offset = 0;
|
|
for (var i = 0; i < node[coll].length; i++) {
|
|
if (node[coll][i] === point) {
|
|
return offset;
|
|
}
|
|
offset += node[coll][i].weight;
|
|
}
|
|
};
|
|
// Return true if the node has a shape, otherwise all links are
|
|
// outgoing.
|
|
node.hasShape = function () {
|
|
var outgoing = 0;
|
|
node.linksTo.forEach(function (link) {
|
|
if (link.outgoing) {
|
|
outgoing++;
|
|
}
|
|
});
|
|
return (!node.linksTo.length ||
|
|
outgoing !== node.linksTo.length);
|
|
};
|
|
this.nodes.push(node);
|
|
}
|
|
return node;
|
|
},
|
|
/**
|
|
* Extend generatePoints by adding the nodes, which are Point objects
|
|
* but pushed to the this.nodes array.
|
|
*/
|
|
generatePoints: function () {
|
|
var chart = this.chart, nodeLookup = {};
|
|
H.Series.prototype.generatePoints.call(this);
|
|
if (!this.nodes) {
|
|
this.nodes = []; // List of Point-like node items
|
|
}
|
|
this.colorCounter = 0;
|
|
// Reset links from previous run
|
|
this.nodes.forEach(function (node) {
|
|
node.linksFrom.length = 0;
|
|
node.linksTo.length = 0;
|
|
node.level = node.options.level;
|
|
});
|
|
// Create the node list and set up links
|
|
this.points.forEach(function (point) {
|
|
if (defined(point.from)) {
|
|
if (!nodeLookup[point.from]) {
|
|
nodeLookup[point.from] = this.createNode(point.from);
|
|
}
|
|
nodeLookup[point.from].linksFrom.push(point);
|
|
point.fromNode = nodeLookup[point.from];
|
|
// Point color defaults to the fromNode's color
|
|
if (chart.styledMode) {
|
|
point.colorIndex = pick(point.options.colorIndex, nodeLookup[point.from].colorIndex);
|
|
}
|
|
else {
|
|
point.color =
|
|
point.options.color || nodeLookup[point.from].color;
|
|
}
|
|
}
|
|
if (defined(point.to)) {
|
|
if (!nodeLookup[point.to]) {
|
|
nodeLookup[point.to] = this.createNode(point.to);
|
|
}
|
|
nodeLookup[point.to].linksTo.push(point);
|
|
point.toNode = nodeLookup[point.to];
|
|
}
|
|
point.name = point.name || point.id; // for use in formats
|
|
}, this);
|
|
// Store lookup table for later use
|
|
this.nodeLookup = nodeLookup;
|
|
},
|
|
// Destroy all nodes on setting new data
|
|
setData: function () {
|
|
if (this.nodes) {
|
|
this.nodes.forEach(function (node) {
|
|
node.destroy();
|
|
});
|
|
this.nodes.length = 0;
|
|
}
|
|
H.Series.prototype.setData.apply(this, arguments);
|
|
},
|
|
// Destroy alll nodes and links
|
|
destroy: function () {
|
|
// Nodes must also be destroyed (#8682, #9300)
|
|
this.data = []
|
|
.concat(this.points || [], this.nodes);
|
|
return H.Series.prototype.destroy.apply(this, arguments);
|
|
},
|
|
/**
|
|
* When hovering node, highlight all connected links. When hovering a link,
|
|
* highlight all connected nodes.
|
|
*/
|
|
setNodeState: function (state) {
|
|
var args = arguments, others = this.isNode ? this.linksTo.concat(this.linksFrom) :
|
|
[this.fromNode, this.toNode];
|
|
if (state !== 'select') {
|
|
others.forEach(function (linkOrNode) {
|
|
if (linkOrNode && linkOrNode.series) {
|
|
Point.prototype.setState.apply(linkOrNode, args);
|
|
if (!linkOrNode.isNode) {
|
|
if (linkOrNode.fromNode.graphic) {
|
|
Point.prototype.setState.apply(linkOrNode.fromNode, args);
|
|
}
|
|
if (linkOrNode.toNode && linkOrNode.toNode.graphic) {
|
|
Point.prototype.setState.apply(linkOrNode.toNode, args);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
Point.prototype.setState.apply(this, args);
|
|
}
|
|
/* eslint-enable valid-jsdoc */
|
|
};
|