/**
|
|
* Definitions for param's in jsdoc.
|
|
* These are more or less global within Network. Putting them here until I can figure out
|
|
* where to really put them
|
|
*
|
|
* @typedef {string|number} Id
|
|
* @typedef {Id} NodeId
|
|
* @typedef {Id} EdgeId
|
|
* @typedef {Id} LabelId
|
|
*
|
|
* @typedef {{x: number, y: number}} point
|
|
* @typedef {{left: number, top: number, width: number, height: number}} rect
|
|
* @typedef {{x: number, y:number, angle: number}} rotationPoint
|
|
* - point to rotate around and the angle in radians to rotate. angle == 0 means no rotation
|
|
* @typedef {{nodeId:NodeId}} nodeClickItem
|
|
* @typedef {{nodeId:NodeId, labelId:LabelId}} nodeLabelClickItem
|
|
* @typedef {{edgeId:EdgeId}} edgeClickItem
|
|
* @typedef {{edgeId:EdgeId, labelId:LabelId}} edgeLabelClickItem
|
|
*/
|
|
|
|
let util = require("../../../../util");
|
|
|
|
/**
|
|
* Helper functions for components
|
|
* @class
|
|
*/
|
|
class ComponentUtil {
|
|
/**
|
|
* Determine values to use for (sub)options of 'chosen'.
|
|
*
|
|
* This option is either a boolean or an object whose values should be examined further.
|
|
* The relevant structures are:
|
|
*
|
|
* - chosen: <boolean value>
|
|
* - chosen: { subOption: <boolean or function> }
|
|
*
|
|
* Where subOption is 'node', 'edge' or 'label'.
|
|
*
|
|
* The intention of this method appears to be to set a specific priority to the options;
|
|
* Since most properties are either bridged or merged into the local options objects, there
|
|
* is not much point in handling them separately.
|
|
* TODO: examine if 'most' in previous sentence can be replaced with 'all'. In that case, we
|
|
* should be able to get rid of this method.
|
|
*
|
|
* @param {string} subOption option within object 'chosen' to consider; either 'node', 'edge' or 'label'
|
|
* @param {Object} pile array of options objects to consider
|
|
*
|
|
* @return {boolean|function} value for passed subOption of 'chosen' to use
|
|
*/
|
|
static choosify(subOption, pile) {
|
|
// allowed values for subOption
|
|
let allowed = [ 'node', 'edge', 'label'];
|
|
let value = true;
|
|
|
|
let chosen = util.topMost(pile, 'chosen');
|
|
if (typeof chosen === 'boolean') {
|
|
value = chosen;
|
|
} else if (typeof chosen === 'object') {
|
|
if (allowed.indexOf(subOption) === -1 ) {
|
|
throw new Error('choosify: subOption \'' + subOption + '\' should be one of '
|
|
+ "'" + allowed.join("', '") + "'");
|
|
}
|
|
|
|
let chosenEdge = util.topMost(pile, ['chosen', subOption]);
|
|
if ((typeof chosenEdge === 'boolean') || (typeof chosenEdge === 'function')) {
|
|
value = chosenEdge;
|
|
}
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
|
|
/**
|
|
* Check if the point falls within the given rectangle.
|
|
*
|
|
* @param {rect} rect
|
|
* @param {point} point
|
|
* @param {rotationPoint} [rotationPoint] if specified, the rotation that applies to the rectangle.
|
|
* @returns {boolean} true if point within rectangle, false otherwise
|
|
* @static
|
|
*/
|
|
static pointInRect(rect, point, rotationPoint) {
|
|
if (rect.width <= 0 || rect.height <= 0) {
|
|
return false; // early out
|
|
}
|
|
|
|
if (rotationPoint !== undefined) {
|
|
// Rotate the point the same amount as the rectangle
|
|
var tmp = {
|
|
x: point.x - rotationPoint.x,
|
|
y: point.y - rotationPoint.y
|
|
};
|
|
|
|
if (rotationPoint.angle !== 0) {
|
|
// In order to get the coordinates the same, you need to
|
|
// rotate in the reverse direction
|
|
var angle = -rotationPoint.angle;
|
|
|
|
var tmp2 = {
|
|
x: Math.cos(angle)*tmp.x - Math.sin(angle)*tmp.y,
|
|
y: Math.sin(angle)*tmp.x + Math.cos(angle)*tmp.y
|
|
};
|
|
point = tmp2;
|
|
} else {
|
|
point = tmp;
|
|
}
|
|
|
|
// Note that if a rotation is specified, the rectangle coordinates
|
|
// are **not* the full canvas coordinates. They are relative to the
|
|
// rotationPoint. Hence, the point coordinates need not be translated
|
|
// back in this case.
|
|
}
|
|
|
|
var right = rect.x + rect.width;
|
|
var bottom = rect.y + rect.width;
|
|
|
|
return (
|
|
rect.left < point.x &&
|
|
right > point.x &&
|
|
rect.top < point.y &&
|
|
bottom > point.y
|
|
);
|
|
}
|
|
}
|
|
|
|
export default ComponentUtil;
|