// During the rave-layouts.js build, this file is added to the top.
// Create an inner self-executing function that will be run with the global scope
// On browsers, this is 'window'. Everywhere else should use 'this' if available.
// Need to run eval('this') "indirectly" by having eval returned by (1,eval). OBVIOUSLY :)
(function (global, factory) {
// dynamically determine how 'rave' variable should be loaded depeneding on loader type
var _rave;
if (typeof module === "object" && typeof module.exports === "object" && typeof require == "function") {
// CommonJS/node.js
var rave = require("rave");
var navigation = factory(global,rave);
module.exports = rave;
} else if (typeof define === "function" && define.amd) {
// AMD
define(['rave'], function(rave) {
return factory(global,rave);
});
} else {
// probably loading via script tag. run as is, setting stuff on rave
factory(global,global['rave']);
}
}((1, eval)('this'), function (_global, _rave) {(function() {
var $ = {};
// $source: com/ibm/rave/ext/internal/layout/nativeImpl/ModuleHeader
/************************************************************************
** IBM Confidential
**
** IBM Business Analytics: Rapidly Adaptive Visualization Engine
**
** (C) Copyright IBM Corp. 2015
**
** The source code for this program is not published or otherwise divested of its trade secrets,
** irrespective of what has been deposited with the U.S. Copyright Office.
************************************************************************/
// setup
var global = typeof _global !== "undefined" ? _global : (1, eval)('this');
var rave = typeof _rave !== "undefined" ? _rave : global['rave'];
com_ibm_rave_core_Rave = rave;
rave["internal"]["Declare"] = rave["_"]["com_ibm_rave_core_nativeImpl_Declare"];
// $source: com/ibm/rave/ext/layout/bubble/BubbleLayout
/************************************************************************
** IBM Confidential
**
** IBM Business Analytics: Rapidly Adaptive Visualization Engine
**
** (C) Copyright IBM Corp. 2017
**
** The source code for this program is not published or otherwise divested of its trade secrets,
** irrespective of what has been deposited with the U.S. Copyright Office.
************************************************************************/
// GENERATED
//@import com/ibm/rave/ext/internal/layout/bubble/SquarePackMethod (runtime) // new
//@import com/ibm/rave/ext/internal/layout/bubble/CirclePackMethod (runtime) // new
/**
* Bubble layout - circle packing into a shape specified by the layout method (circle being a default) Bubble layout returns sorted collection of nodes with calculated coordinates x,y, with radius set respective to the radius function or value. Collection of nodes will be sorted according to the sort function, however, sort order of the nodes does not influence coordinates calculated by bubble packing algorithm
*/
var com_ibm_rave_ext_layout_bubble_BubbleLayout = rave['internal']['Declare'](rave['internal']['AbstractPackLayout'], {
//methodVal : null,
constructor : function() {
this.methodVal = "circle";
/**
* constructor
*/
{
this.sort(null);
}
},
/**
* Runs the bubble layout, returning the array of nodes associated with the specified root node. The bubble layout is part of the family of hierarchical layouts. These layouts follow the same basic structure: the input argument to the layout is the root node of the hierarchy, and the output return value is an array representing the computed positions of all nodes. Several attributes are populated on each node: parent - the parent node, or null for the root. children - the array of child nodes, or null for leaf nodes. value - the node value, as returned by the value accessor. depth - the depth of the node, starting at 0 for the root. x - the computed x-coordinate of the node position. y - the computed y-coordinate of the node position. r - the computed node radius.
* @param d the root node
* @param i index
* @return (Array) Array or positioned nodes
*/
/** @expose */
create : function(root) {
var nodes = rave['internal']['HierarchyBase'].prototype.create.call(this, root);
var localR;
if (!this.radiusFn && this.radiusVal == null) {
localR = com_ibm_rave_ext_layout_bubble_BubbleLayout.DEFAULT_FN;
} else if (!this.radiusFn) {
localR = new rave['internal']['ConstantSingleValueFunction'](this.radiusVal);
} else {
localR = this.radiusFn;
}
root["x"] = root["y"] = 0;
rave['internal']['HierarchyUtil'].visitAfter(root, new (rave['internal']['Declare']({
visit : function(node) {
node["r"] = + (localR(node["value"]));
}
}))());
var extent = [this.sizeVal[0], this.sizeVal[1]];
var type = this.method();
rave['internal']['HierarchyUtil'].visitAfter(root, new (rave['internal']['Declare']({
visit : function(node) {
var algorithm = "square" == type ? new com_ibm_rave_ext_internal_layout_bubble_SquarePackMethod(extent) : new com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod(extent);
algorithm.pack(node);
}
}))());
var x = extent[0] / 2, y = extent[1] / 2;
var scale = (this.radiusFn || (this.radiusVal)) ? 1 : 1 / Math.max(2 * root["r"] / extent[0], 2 * root["r"] / extent[1]);
var dr = (this.padding()) ? this.padding() / 2 : 0;
this.layout_packTransform(root, x, y, scale, dr);
return nodes;
},
/**
* Sets the value of layout method variant(circle, square, etc).Packing algorithm will be chosen based on the method, e.g. CIRCLE
method will produce packing bubbles into a circle, SQUARE
will pack bubbles into a square. Some layout methods work best on flat data structures.
* @param - value of layout method variant. If set to SQUARE
for example, the layout will be done to fit a square rather than a circle. CIRCLE
by default
* @return (com.ibm.rave.ext.layout.bubble.BubbleLayout) this layout
*/
method$0 : function(value) {
var _method = value.toString();
if ("circle" == _method) {
this.methodVal = "circle";
return this;
}
if ("square" == _method) {
this.methodVal = "square";
return this;
}
this.methodVal = "circle";
return this;
},
/**
* @return (String) - Return the value of layout method variant (e.g. circle, square, etc).
*/
method$1 : function() {
return this.methodVal;
},
/** @expose */
layout_packTransform : function(node, x, y, scale, _padding) {
var _x = x;
var _y = y;
var children = node["children"];
node["x"] = (_x += scale * node["x"]);
node["y"] = (_y += scale * node["y"]);
node["r"] *= scale;
node["r"] -= _padding;
node["r"] = Math.max(0.0, node["r"]);
if (children) {
var i = -1, n = children.length;
while (++i < n) {
this.layout_packTransform(children[i], node["x"], node["y"], scale, _padding);
}
}
},
/** @expose */
method : function(a0) {
var args = arguments;
if (args.length == 0) {
return this.method$1();
}
return this.method$0(a0);
}
});
/**
* identifies packing method as packing all shapes into a circle shape
*/
/** @expose */
com_ibm_rave_ext_layout_bubble_BubbleLayout.CIRCLE = "circle";
/**
* identifies packing method as packing all shapes into a square shape, works best on flat data structures
*/
/** @expose */
com_ibm_rave_ext_layout_bubble_BubbleLayout.SQUARE = "square";
com_ibm_rave_ext_layout_bubble_BubbleLayout.DEFAULT_FN = function(data) {
return + (data);
};
// $source: com/ibm/rave/ext/internal/layout/bubble/BubblePackLayoutMethod
/************************************************************************
** IBM Confidential
**
** IBM Business Analytics: Rapidly Adaptive Visualization Engine
**
** (C) Copyright IBM Corp. 2017
**
** The source code for this program is not published or otherwise divested of its trade secrets,
** irrespective of what has been deposited with the U.S. Copyright Office.
************************************************************************/
// GENERATED
/**
* A bubble pack algorithm variant. Defines boundaries of the layout as a geometric shape - circle, square, etc
*/
var com_ibm_rave_ext_internal_layout_bubble_BubblePackLayoutMethod = rave['internal']['Declare']({
/**
* Run algorithm and calculate x,y positions of each node
* @param (Object) root root node
*/
//pack : function(root) {}
});
com_ibm_rave_ext_internal_layout_bubble_BubblePackLayoutMethod.hypot = function(a, b) {
return Math.sqrt(a * a + b * b);
};
com_ibm_rave_ext_internal_layout_bubble_BubblePackLayoutMethod.distance = function(p1, p2) {
return com_ibm_rave_ext_internal_layout_bubble_BubblePackLayoutMethod.hypot(p1[0] - p2[0], p1[1] - p2[1]);
};
// $source: com/ibm/rave/ext/internal/layout/utils/Qtree
/************************************************************************
** IBM Confidential
**
** IBM Business Analytics: Rapidly Adaptive Visualization Engine
**
** (C) Copyright IBM Corp. 2017
**
** The source code for this program is not published or otherwise divested of its trade secrets,
** irrespective of what has been deposited with the U.S. Copyright Office.
************************************************************************/
// GENERATED
/**
* Spatial quad tree a homogeneous collection of objects of type T, each represented by a rectangular node with extent x,y,width,height
* @param < (java.lang.Object) T > type of the item attached to qtree rectangle node
* @see (Object) QTreeNode
*/
var com_ibm_rave_ext_internal_layout_utils_Qtree = rave['internal']['Declare']({
//objects : null,
//bounds : null,
//quadrants : null,
/**
* maximum number of objects for any level before it splits
*/
max_objects : 30,
/**
* maximum number of levels this tree can handle
*/
MAX_LEVELS : 15,
size : 0,
level : 0,
subWidth : 0,
subHeight : 0,
xMidpoint : 0,
yMidpoint : 0,
constructor : function(pLevel, pBounds) {
this.level = pLevel;
this.objects = [];
this.bounds = pBounds;
this.subWidth = this.bounds["width"] / 2;
this.subHeight = this.bounds["height"] / 2;
this.xMidpoint = this.bounds["x"] + this.subWidth;
this.yMidpoint = this.bounds["y"] + this.subHeight;
},
/**
* Clears the quadtree
*/
clear : function() {
this.objects = [];
this.quadrants = null;
this.size = 0;
},
split : function() {
this.quadrants = [];
this.quadrants[1] = new com_ibm_rave_ext_internal_layout_utils_Qtree(this.level + 1, com_ibm_rave_ext_internal_layout_utils_Qtree.newQTreeNode(this.bounds["x"], this.bounds["y"] + this.subHeight, this.subWidth, this.subHeight, null));
this.quadrants[0] = new com_ibm_rave_ext_internal_layout_utils_Qtree(this.level + 1, com_ibm_rave_ext_internal_layout_utils_Qtree.newQTreeNode(this.bounds["x"] + this.subWidth, this.bounds["y"] + this.subHeight, this.subWidth, this.subHeight, null));
this.quadrants[2] = new com_ibm_rave_ext_internal_layout_utils_Qtree(this.level + 1, com_ibm_rave_ext_internal_layout_utils_Qtree.newQTreeNode(this.bounds["x"], this.bounds["y"], this.subWidth, this.subHeight, null));
this.quadrants[3] = new com_ibm_rave_ext_internal_layout_utils_Qtree(this.level + 1, com_ibm_rave_ext_internal_layout_utils_Qtree.newQTreeNode(this.bounds["x"] + this.subWidth, this.bounds["y"], this.subWidth, this.subHeight, null));
var new_objects = [];
for (var __i_enFor0 = 0, __exp_enFor0 = this.objects, __len_enFor0 = __exp_enFor0.length;
__i_enFor0 < __len_enFor0; ++__i_enFor0) {
var node = __exp_enFor0[__i_enFor0];
var index = this.getQuadrant(node);
if (index != -1) {
this.quadrants[index].insert(node);
} else {
new_objects.push(node);
}
}
this.objects = new_objects;
},
getQuadrant : function(pRect) {
if (pRect["width"] > this.subWidth || pRect["height"] > this.subHeight) {
return -1;
}
var topQuadrant = pRect["y"] >= this.yMidpoint;
var bottomQuadrant = pRect["y"] + pRect["height"] <= this.yMidpoint;
if (pRect["x"] >= this.xMidpoint) {
if (topQuadrant) {
return 0;
}
if (bottomQuadrant) {
return 3;
}
}
if (pRect["x"] + pRect["width"] <= this.xMidpoint) {
if (topQuadrant) {
return 1;
}
if (bottomQuadrant) {
return 2;
}
}
return -1;
},
/**
* Insert the object into the quadtree. If the node exceeds the capacity, the tree will split and add all objects to their corresponding quadrants.
* @param (Object) pRect
*/
insert : function(pRect) {
this.size++;
if (this.quadrants) {
var index = this.getQuadrant(pRect);
if (index != -1) {
this.quadrants[index].insert(pRect);
return;
}
}
this.objects.push(pRect);
if (!this.quadrants && this.objects.length > this.max_objects && this.level < this.MAX_LEVELS) {
this.split();
}
},
/**
* Returns true if the test rectangle r intersects bounds of this tree, false otherwise
* @param r rectangle to test for intersection with this tree
* @return (boolean) true if the test rectangle r intersects bounds of this tree, false otherwise
*/
intersectsRectangle : function(rect) {
return this.intersects(rect["x"], rect["y"], rect["width"], rect["height"]);
},
intersects : function(x, y, width, height) {
return (x < this.bounds["x"] + this.bounds["width"]) && (y < this.bounds["y"] + this.bounds["height"]) && (x + width > this.bounds["x"]) && (y + height > this.bounds["y"]);
},
/**
* Evaluate collision tester function against all nodes that have the potential of colliding with the test rectangle. Return true, if test rectangle does collide with any of the nodes, false otherwise This method allows to test while iterating and bail out as soon as tester function returns true
* @param (rave['internal']['SingleValueFunction']) tester a function to execute on each tree node to test wither or not it will collide with pRect
* @param (Object) test a rectangle to test wither or not it will collide with any
* @return (boolean) true if object does collide with any node in the tree, false otherwise
*/
collide : function(tester, test) {
if (this.quadrants) {
for (var i = 0; i < 4; ++i) {
if (this.quadrants[i].intersectsRectangle(test)) {
if (this.quadrants[i].collide(tester, test)) {
return true;
}
}
}
}
for (var __i_enFor0 = 0, __exp_enFor0 = this.objects, __len_enFor0 = __exp_enFor0.length;
__i_enFor0 < __len_enFor0; ++__i_enFor0) {
var node = __exp_enFor0[__i_enFor0];
if (tester(node)) {
return true;
}
}
return false;
}
});
/**
* Create new tree node with an rectangle extent x,y,width, height and an item it points to
* @param (double) x rectangle x
* @param (double) y rectangle y
* @param (double) width rectangle width
* @param (double) height rectangle height
* @param (java.lang.Object) item an object represented by the rectangle
* @return (Object) new rectangle node object
*/
com_ibm_rave_ext_internal_layout_utils_Qtree.newQTreeNode = function(x, y, width, height, item) {
var node = {};
node["x"] = x;
node["y"] = y;
node["width"] = width;
node["height"] = height;
node["item"] = item;
return node;
};
com_ibm_rave_ext_internal_layout_utils_Qtree.TOP_RIGHT = 0;
com_ibm_rave_ext_internal_layout_utils_Qtree.TOP_LEFT = 1;
com_ibm_rave_ext_internal_layout_utils_Qtree.BOTTOM_LEFT = 2;
com_ibm_rave_ext_internal_layout_utils_Qtree.BOTTOM_RIGHT = 3;
// $source: com/ibm/rave/ext/internal/layout/utils/DoubleUtils
/************************************************************************
** IBM Confidential
**
** IBM Business Analytics: Rapidly Adaptive Visualization Engine
**
** (C) Copyright IBM Corp. 2017
**
** The source code for this program is not published or otherwise divested of its trade secrets,
** irrespective of what has been deposited with the U.S. Copyright Office.
************************************************************************/
// GENERATED
var com_ibm_rave_ext_internal_layout_utils_DoubleUtils = {
};
/**
* Compares the two specified {@code double} values. The sign of the integer value returned is the same as that of the integer that would be returned by the call:
new Double(d1).compareTo(new Double(d2))* @param (double) d1 the first {@code double} to compare * @param (double) d2 the second {@code double} to compare * @return (int) the value {@code 0} if {@code d1} is numerically equal to {@code d2} ; a value less than {@code 0} if {@code d1} is numerically less than {@code d2} ; and a value greater than {@code 0} if {@code d1} is numerically greater than {@code d2} . */ com_ibm_rave_ext_internal_layout_utils_DoubleUtils.compare = function(d1, d2) { if (d1 < d2) { return -1; } if (d1 > d2) { return 1; } return d1 == d2 ? 0 : isNaN(d1) ? -1 : 1; }; // $source: com/ibm/rave/ext/layout/fill/FillLayout /************************************************************************ ** IBM Confidential ** ** IBM Business Analytics: Rapidly Adaptive Visualization Engine ** ** (C) Copyright IBM Corp. 2017 ** ** The source code for this program is not published or otherwise divested of its trade secrets, ** irrespective of what has been deposited with the U.S. Copyright Office. ************************************************************************/ // GENERATED /** * Fill layout. This layout is similar to the bubble layout in that it packs shapes together and may be applied to shapes of different sizes. The order of the packing is not specified and there is no attempt to place the larger shapes at the beginning or in the center. The Fill layout treats shapes as rectangles and packs them in either column-major (the default) or row-major order. In the major direction the shapes all take the same width or height, equal to that of the largest shape. In the minor direction the shapes may either all have the same size equal to that of the largest shape, or each may use exactly their own size. Padding may be applied to the shapes with the padding property of the layout specification. If there is not enough room to fit all the shapes, a custom error callback can be attached to inform about details of the remaining shapes */ var com_ibm_rave_ext_layout_fill_FillLayout = rave['internal']['Declare']({ //hAlignVal : null, //vAlignVal : null, //methodVal : null, //directionVal : null, //rowOrderVal : null, //columnOrderVal : null, //sizeVal : null, //gridCellSize : null, //cellSizeFn : null, //errorCallback : null, rowsVal : 0, columnsVal : 0, paddingVal : 0, /** * The number of horizontal and vertical cells that are laid out by the grid */ numberOfVerticalCellsVal : -1, numberOfHorizontalCellsVal : -1, _$functionClassMethod : function() { var _$self = /** * Layout the collection of data nodes * @param (Array) nodes data nodes collection * @return (Array) a collection of data nodes, which were successfully laid out , with calculated x,y */ function(nodes) { if (!_$self.cellSizeFn) { var sizeLocal = _$self.size(); var c = _$self.columns(); var r = _$self.rows(); var p = _$self.padding(); _$self.cellSizeFn = function(node) { var width = sizeLocal[0]; var height = sizeLocal[1]; node["width"] = (width - p * c) / c; node["height"] = (height - p * r) / r; }; } for (var __i_enFor0 = 0, __exp_enFor0 = nodes, __len_enFor0 = __exp_enFor0.length; __i_enFor0 < __len_enFor0; ++__i_enFor0) { var node = __exp_enFor0[__i_enFor0]; node["x"] = 0; node["y"] = 0; _$self.cellSize()(node); } _$self.layout_computeCellSize(nodes); var numRows = Math.max(Math.floor(_$self.size()[1] / _$self.gridCellSize[1]), 1); var numColumns = Math.max(Math.floor(_$self.size()[0] / _$self.gridCellSize[0]), 1); if (_$self.rows() > 0) { numRows = Math.min(numRows, _$self.rows()); } if (_$self.columns() > 0) { numColumns = Math.min(numColumns, _$self.columns()); } if ("packed" == _$self.method()) { if ("row" == _$self.direction()) { numColumns = Math.max(0, _$self.columns()); } else { numRows = Math.max(0, _$self.rows()); } } return _$self.layout_packShapes(nodes, numRows, numColumns); }; return _$self; }, constructor : function() { this.hAlignVal = "start"; this.vAlignVal = "middle"; this.methodVal = "packed"; this.directionVal = "column"; this.rowOrderVal = "down"; this.columnOrderVal = "left"; this.sizeVal = [1.0, 1.0]; }, /** * Returns method which controls the spacing in the minor direction. "packed" (the default) makes each shape use its own size. "grid" makes all shapes use the same spacing. * @return (String) packing method */ method$0 : function() { return this.methodVal; }, /** * Set method, which controls the spacing in the minor direction. "packed" (the default) makes each shape use its own size. "grid" makes all shapes use the same spacing. * @return (com.ibm.rave.ext.layout.fill.FillLayout) this */ method$1 : function(method) { if ("grid" == method) { this.methodVal = "grid"; } else { this.methodVal = "packed"; } return this; }, /** * Return the packing major direction. "column" is the default, "row" is the other option. * @return (String) the packing major direction. "column" is the default, "row" is the other option. */ direction$0 : function() { return this.directionVal; }, /** * Sets the packing major direction. "column" is the default, "row" is the other option. * @param (String) direction "column" or "row" * @return (com.ibm.rave.ext.layout.fill.FillLayout) this */ direction$1 : function(direction) { if ("row" == direction) { this.directionVal = "row"; } else { this.directionVal = "column"; } return this; }, /** * Sets the number of rows. If the layout direction is row, the layout will expand to have the given number of rows. If the layout direction is column no more than this number of shapes will be placed in any column. * @param (Object) rows the number of rows * @return (com.ibm.rave.ext.layout.fill.FillLayout) this */ rows$0 : function(rows) { this.rowsVal = ~~ (rows); return this; }, /** * Returns the number of rows. If the layout direction is row, the layout will expand to have the given number of rows. If the layout direction is column no more than this number of shapes will be placed in any column. * @return (int) number of rows */ rows$1 : function() { return this.rowsVal; }, /** * Sets the number of columns. If the layout direction is column, the layout will expand to have the given number of columns. If the layout direction is row , no more than this number of shapes will be placed in any row. * @param (Object) columns number of columns * @return (com.ibm.rave.ext.layout.fill.FillLayout) this */ columns$0 : function(columns) { this.columnsVal = ~~ (columns); return this; }, /** * Returns the number of columns. If the layout direction is column, the layout will expand to have the given number of columns. If the layout direction is row , no more than this number of shapes will be placed in any row. * @return (int) number of columns */ columns$1 : function() { return this.columnsVal; }, /** * Sets the order used to determines whether the rows are filled from "top-to-bottom" (the default) or "bottom-to-top". Note that the direction within each row is controlled by the column order. * @param (String) order "top-to-bottom" (the default) or "bottom-to-top" * @return (com.ibm.rave.ext.layout.fill.FillLayout) this */ rowOrder$0 : function(order) { if ("down" == order) { this.rowOrderVal = "down"; } else { this.rowOrderVal = "up"; } return this; }, /** * Returns the order used to determines whether the rows are filled from "top-to-bottom" (the default) or "bottom-to-top". Note that the direction within each row is controlled by the column order. * @return (String) row order used to determines whether the rows are filled from "top-to-bottom" (the default) or "bottom-to-top". */ rowOrder$1 : function() { return this.rowOrderVal; }, /** * Sets the order used to determines whether the columns are filled from "left-to-right" (the default) or "right-to-left". Note that the direction within each row is controlled by the row order. * @param (String) order the order used to determines whether the columns are filled from "left-to-right" (the default) or "right-to-left". * @return (com.ibm.rave.ext.layout.fill.FillLayout) this */ columnOrder$0 : function(order) { if ("right" == order) { this.columnOrderVal = "right"; } else { this.columnOrderVal = "left"; } return this; }, /** * Returns the order used to determines whether the columns are filled from "left-to-right" (the default) or "right-to-left". Note that the direction within each row is controlled by the row order. * @return (String) */ columnOrder$1 : function() { return this.columnOrderVal; }, /** * Returns the current size, which defaults to 1x1 * @return (double[]) return the current size */ size$0 : function() { return this.sizeVal; }, /** * Sets the available layout size to the specified two-element array of numbers representing width and height. * @param (double[]) newSize the size of the layout * @return (com.ibm.rave.ext.layout.fill.FillLayout) this Layout */ size$1 : function(newSize) { this.sizeVal = newSize; return this; }, /** * Set padding * @param (Object) padding layout padding between elements * @return (com.ibm.rave.ext.layout.fill.FillLayout) this */ padding$0 : function(padding) { this.paddingVal = + (padding); return this; }, /** * Return padding set for nodes * @return (double) layout padding value */ padding$1 : function() { return this.paddingVal; }, /** * Set vertical node alignment - "start", "end" or "middle" * @param (String) alignment vertical node alignment "start", "end" or "middle", "middle" being a default * @return (com.ibm.rave.ext.layout.fill.FillLayout) this */ valign$0 : function(alignment) { if ("start" == alignment) { this.vAlignVal = "start"; } else if ("end" == alignment) { this.vAlignVal = "end"; } else { this.vAlignVal = "middle"; } return this; }, /** * @return (String) vertical node alignment ("start", "end" or "middle", "middle" being a default) */ valign$1 : function() { return this.vAlignVal; }, /** * Set horizontal node alignment to "start", "end" or "middle", "start" being a default * @param (String) alignment horizontal node alignment to "start", "end" or "middle", "start" being a default * @return (com.ibm.rave.ext.layout.fill.FillLayout) this */ halign$0 : function(alignment) { if ("middle" == alignment) { this.hAlignVal = "middle"; } else if ("end" == alignment) { this.hAlignVal = "end"; } else { this.hAlignVal = "start"; } return this; }, /** * @return (String) horizontal node alignment ( "start", "end" or "middle", "start" being a default) */ halign$1 : function() { return this.hAlignVal; }, /** * Set function, which will assign width and height of an individual node * @param (com.ibm.rave.ext.layout.fill.SetValueFunction) fn function, which will assign width and height of an individual node * @return (com.ibm.rave.ext.layout.fill.FillLayout) this */ cellSize$0 : function(fn) { this.cellSizeFn = fn; return this; }, /** * Return function, which will assign width and height of an individual node * @return (com.ibm.rave.ext.layout.fill.SetValueFunction) function, which will assign width and height of an individual node */ cellSize$1 : function() { return this.cellSizeFn; }, /** * Set function, which will be invoked, when a node does not fit * @param function function, which will be invoked, when a node does not fit * @return (com.ibm.rave.ext.layout.fill.FillLayout) this * @see DoesNotFitCallback */ error$0 : function(fn) { this.errorCallback = fn; return this; }, /** * Return function, which will be invoked, when a node does not fit * @return (com.ibm.rave.ext.layout.fill.DoesNotFitCallback) function, which will be invoked, when a node does not fit * @see DoesNotFitCallback */ error$1 : function() { return this.errorCallback; }, layout_computeCellSize : function(nodes) { var maxW = 1.0; var maxH = 1.0; for (var __i_enFor0 = 0, __exp_enFor0 = nodes, __len_enFor0 = __exp_enFor0.length; __i_enFor0 < __len_enFor0; ++__i_enFor0) { var node = __exp_enFor0[__i_enFor0]; maxW = Math.max(maxW, node["width"]); maxH = Math.max(maxH, node["height"]); } this.gridCellSize = [maxW + this.padding(), maxH + this.padding()]; }, layout_packShapes : function(nodes, numRows, numColumns) { var result = []; this.numberOfVerticalCellsVal = -1; this.numberOfHorizontalCellsVal = -1; var reportDoNotFit = this.error(); var didNotFit; if (reportDoNotFit) { didNotFit = []; for (var __i_enFor0 = 0, __exp_enFor0 = nodes, __len_enFor0 = __exp_enFor0.length; __i_enFor0 < __len_enFor0; ++__i_enFor0) { var node = __exp_enFor0[__i_enFor0]; didNotFit.push(node); } } var shapeCount = nodes.length; var shapeIndex = 0; var gridMethod = "grid" == this.method(); var majorCount; var majorShapeSize; var majorChartSize; var minorCount; var minorShapeSize; var minorChartSize; if ("row" == this.direction()) { majorCount = numRows; minorCount = numColumns; majorShapeSize = this.gridCellSize[1]; majorChartSize = this.size()[1]; minorChartSize = this.size()[0]; } else { majorCount = numColumns; minorCount = numRows; majorShapeSize = this.gridCellSize[0]; majorChartSize = this.size()[0]; minorChartSize = this.size()[1]; } if (minorCount == 0) { minorCount = ~~minorChartSize; } var majorPosition = 0.0; var minorPosition = 0.0; var majorIndex = 0; var minorIndex = 0; var last; while (shapeIndex < shapeCount && majorIndex < majorCount) { majorPosition = majorIndex * majorShapeSize; minorPosition = 0.0; minorIndex = 0; while (shapeIndex < shapeCount && minorIndex < minorCount) { var node = nodes[shapeIndex]; if (gridMethod) { minorShapeSize = ("row" == this.direction()) ? this.gridCellSize[0] : this.gridCellSize[1]; } else { minorShapeSize = ("row" == this.direction()) ? node["width"] + this.padding() : node["height"] + this.padding(); } if (!gridMethod && minorShapeSize > minorChartSize) { shapeIndex++; continue; } if (minorPosition + minorShapeSize <= minorChartSize && majorPosition <= majorChartSize) { this.layout_placeShape(node, majorPosition, minorPosition, majorShapeSize, minorShapeSize, 0); result.push(node); if (reportDoNotFit) { didNotFit[shapeIndex] = null; last = node; } shapeIndex++; minorIndex++; minorPosition += minorShapeSize; } else { break; } } if ("row" == this.direction()) { this.numberOfHorizontalCellsVal = Math.max(minorIndex, this.numberOfHorizontalCellsVal); } else { this.numberOfVerticalCellsVal = Math.max(minorIndex, this.numberOfVerticalCellsVal); } majorIndex++; } if ("row" == this.direction()) { this.numberOfVerticalCellsVal = majorIndex; } else { this.numberOfHorizontalCellsVal = majorIndex; } if (reportDoNotFit) { var orphans = []; for (var __i_enFor1 = 0, __exp_enFor1 = didNotFit, __len_enFor1 = __exp_enFor1.length; __i_enFor1 < __len_enFor1; ++__i_enFor1) { var node = __exp_enFor1[__i_enFor1]; if (node) { orphans.push(node); } } if (shapeIndex < shapeCount || orphans.length > 0) { this.error()(!last ? NaN : last["x"], !last ? NaN : last["y"], orphans); } } return result; }, layout_placeShape : function(node, majorPosition, minorPosition, majorSize, minorSize, deltaX) { var xpos; var ypos; var xsize; var ysize; if ("row" == this.direction()) { xpos = minorPosition; ypos = majorPosition; xsize = minorSize; ysize = majorSize; } else { xpos = majorPosition; ypos = minorPosition; xsize = majorSize; ysize = minorSize; } if ("up" == this.rowOrder()) { ypos = this.size()[1] - ypos - ysize; } if ("right" == this.columnOrder()) { xpos = this.size()[0] - xpos - xsize; } xpos += this.padding(); ypos += this.padding(); xpos += deltaX; var availableX = xsize - node["width"] - deltaX - this.padding(); var availableY = ysize - node["height"] - this.padding(); if ("middle" == this.halign()) { xpos += availableX / 2.0; } else if ("end" == this.halign()) { xpos += availableX; } if ("middle" == this.valign()) { ypos += availableY / 2.0; } else if ("end" == this.valign()) { ypos += availableY; } node["x"] = xpos - node["x"]; node["y"] = ypos - node["y"]; }, /** * @return (int) -1 if the layout hasn't been run, otherwise return the number of vertical cells the layout lays out */ /** @expose */ numberOfVerticalCells : function() { return this.numberOfVerticalCellsVal; }, /** * @return (int) -1 if the layout hasn't been run, otherwise return the number of horizontal cells the layout lays out */ /** @expose */ numberOfHorizontalCells : function() { return this.numberOfHorizontalCellsVal; }, /** @expose */ method : function(a0) { var args = arguments; if (args.length == 0) { return this.method$0(); } return this.method$1(a0); }, /** @expose */ direction : function(a0) { var args = arguments; if (args.length == 0) { return this.direction$0(); } return this.direction$1(a0); }, /** @expose */ rows : function(a0) { var args = arguments; if (args.length == 0) { return this.rows$1(); } return this.rows$0(a0); }, /** @expose */ columns : function(a0) { var args = arguments; if (args.length == 0) { return this.columns$1(); } return this.columns$0(a0); }, /** @expose */ rowOrder : function(a0) { var args = arguments; if (args.length == 0) { return this.rowOrder$1(); } return this.rowOrder$0(a0); }, /** @expose */ columnOrder : function(a0) { var args = arguments; if (args.length == 0) { return this.columnOrder$1(); } return this.columnOrder$0(a0); }, /** @expose */ size : function(a0) { var args = arguments; if (args.length == 0) { return this.size$0(); } return this.size$1(a0); }, /** @expose */ padding : function(a0) { var args = arguments; if (args.length == 0) { return this.padding$1(); } return this.padding$0(a0); }, /** @expose */ valign : function(a0) { var args = arguments; if (args.length == 0) { return this.valign$1(); } return this.valign$0(a0); }, /** @expose */ halign : function(a0) { var args = arguments; if (args.length == 0) { return this.halign$1(); } return this.halign$0(a0); }, /** @expose */ cellSize : function(a0) { var args = arguments; if (args.length == 0) { return this.cellSize$1(); } return this.cellSize$0(a0); }, /** @expose */ error : function(a0) { var args = arguments; if (args.length == 0) { return this.error$1(); } return this.error$0(a0); } }); /** * packing method "packed" (default) */ /** @expose */ com_ibm_rave_ext_layout_fill_FillLayout.PACKED = "packed"; /** * packing method "grid" */ /** @expose */ com_ibm_rave_ext_layout_fill_FillLayout.GRID = "grid"; /** * packing direction row oriented */ /** @expose */ com_ibm_rave_ext_layout_fill_FillLayout.ROW = "row"; /** * packing direction column oriented (default) */ /** @expose */ com_ibm_rave_ext_layout_fill_FillLayout.COLUMN = "column"; /** * vertical alignment from top down to bottom (default) */ /** @expose */ com_ibm_rave_ext_layout_fill_FillLayout.DOWN = "down"; /** * vertical alignment from bottom up to top */ /** @expose */ com_ibm_rave_ext_layout_fill_FillLayout.UP = "up"; /** * horizontal alignment from left to right (default) */ /** @expose */ com_ibm_rave_ext_layout_fill_FillLayout.LEFT = "left"; /** * horizontal alignment from right to left */ /** @expose */ com_ibm_rave_ext_layout_fill_FillLayout.RIGHT = "right"; /** * Shape alignment */ /** @expose */ com_ibm_rave_ext_layout_fill_FillLayout.ALIGN_START = "start"; /** @expose */ com_ibm_rave_ext_layout_fill_FillLayout.ALIGN_END = "end"; /** @expose */ com_ibm_rave_ext_layout_fill_FillLayout.ALIGN_MIDDLE = "middle"; // $source: com/ibm/rave/ext/layout/hexbin/Hexbin /************************************************************************ ** IBM Confidential ** ** IBM Business Analytics: Rapidly Adaptive Visualization Engine ** ** (C) Copyright IBM Corp. 2017 ** ** The source code for this program is not published or otherwise divested of its trade secrets, ** irrespective of what has been deposited with the U.S. Copyright Office. ************************************************************************/ // GENERATED /** * The hexbin plugin implements hexagonal binning, which is useful for aggregating data into a more coarse representation suitable for display. Rather than displaying a scatterplot with tens of thousands of points, you can bin points into gridded hexagons, and then display the distribution using color or area. */ var com_ibm_rave_ext_layout_hexbin_Hexbin = rave['internal']['Declare']({ //xFunc : null, //yFunc : null, width : 1, height : 1, r : 0, dx : 0, dy : 0, _$functionClassMethod : function() { var _$self = /** * Evaluates the hexbin layout on the specified array of points, returning an array of hexagonal bins. Each bin is an array containing the bin's points, as well as some additional properties: x - the x-coordinate of the center of the associated bin's hexagon y - the y-coordinate of the center of the associated bin's hexagon Bins that are empty are not omitted. The origin bin at {0,0} is in the top-left. The returned bins are designed to work with the layouts point and hexagon methods. * @param (Array) points An array of points to be binned. * @return (Array) an array of hexagonal bins. */ function(points) { var binsById = rave['internal']['ES6Map'].create(); for (var i = 0; i < points.length; ++i) { var point = points[i]; var py = _$self.yFunc(point, i) / _$self.dy; var pj = Math.round(py); var px = _$self.xFunc(point, i) / _$self.dx - ((~~pj & 1) == 1 ? 0.5 : 0.0); var pi = Math.round(px); var py1 = py - pj; if (Math.abs(py1) * 3 > 1) { var px1 = px - pi; var pi2 = pi + (px < pi ? -1 : 1) / 2.0; var pj2 = pj + (py < pj ? -1 : 1); var px2 = px - pi2; var py2 = py - pj2; if (px1 * px1 + py1 * py1 > px2 * px2 + py2 * py2) { pi = pi2 + ((~~pj & 1) == 1 ? 1 : -1) / 2.0; pj = pj2; } } var id = pi + "-" + pj; var bin = binsById.get(id); if (bin) { bin.push(point); } else { bin = []; bin.push(point); binsById.set(id, bin); bin["i"] = pi; bin["j"] = pj; bin["x"] = (pi + ((~~pj & 1) == 1 ? 0.5 : 0)) * _$self.dx; bin["y"] = pj * _$self.dy; } } return binsById.values(); }; return _$self; }, constructor : function() { this.xFunc = com_ibm_rave_ext_layout_hexbin_Hexbin.hexbinX; this.yFunc = com_ibm_rave_ext_layout_hexbin_Hexbin.hexbinY; { this.radius(1); } }, /** * Sets the x-accessor function for the hexbin layout. * @param (com.ibm.rave.ext.layout.hexbin.Hexbin.HexbinFunction) accessor An x-accessor function. * @return (com.ibm.rave.ext.layout.hexbin.Hexbin) this Hexbin instance. */ x$0 : function(accessor) { this.xFunc = accessor; return this; }, /** * Gets the x-accessor function for the hexbin layout. The default is function(d) { return d[0]; }. * @return (com.ibm.rave.ext.layout.hexbin.Hexbin.HexbinFunction) the x-accessor function. */ x$1 : function() { return this.xFunc; }, /** * Sets the y-accessor function for the hexbin layout. * @param (com.ibm.rave.ext.layout.hexbin.Hexbin.HexbinFunction) accessor A y-accessor function. * @return (com.ibm.rave.ext.layout.hexbin.Hexbin) this Hexbin instance. */ y$0 : function(accessor) { this.yFunc = accessor; return this; }, /** * Gets the y-accessor function for the hexbin layout. The default is function(d) { return d[1]; }. * @return (com.ibm.rave.ext.layout.hexbin.Hexbin.HexbinFunction) the y-accessor function. */ y$1 : function() { return this.yFunc; }, /** * Returns the SVG path string for the hexagon centered at the origin {0,0}. The path string is defined with relative coordinates such that you can easily translate the hexagon to the desired position. * @param (double) radius Radius of the hexagon to be used. * @return (String) a hexagon with the specified radius. */ hexagon$0 : function(radius) { return "m" + com_ibm_rave_ext_layout_hexbin_Hexbin._hexagon(radius).join("l") + "z"; }, /** * Returns the SVG path string for the hexagon centered at the origin {0,0}. The path string is defined with relative coordinates such that you can easily translate the hexagon to the desired position. * @return (String) a hexagon with the Hexbin's current radius, which defaults to 1. */ hexagon$1 : function() { return "m" + com_ibm_rave_ext_layout_hexbin_Hexbin._hexagon(this.r).join("l") + "z"; }, /** * Returns an array of [x, y] points representing the centers of each hexagon. Each point also has properties i and j representing the grid column and row, respectively, of the hexagon. * @return (Array) an array of hexbin centers. */ /** @expose */ centers : function() { var centers = []; var odd = false; for (var y = 0, j = 0; y < this.height + this.r; y += this.dy, odd = !odd, ++j) { for (var x = odd ? this.dx / 2 : 0, i = 0; x < this.width + this.dx / 2; x += this.dx, ++i) { var center = []; center["x"] = x; center["y"] = y; center["i"] = i; center["j"] = j; centers.push(center); } } return centers; }, /** * Returns the SVG path string for a hexagonal mesh that covers the area of the layout (as determined by the layout size). The returned mesh is designed to be stroked. The mesh may extend slightly beyond the layout's defined area, and thus may need to be clipped. * @return (String) an SVG Path string. */ /** @expose */ mesh : rave['internal']['Declare'].bind(function() { var fragment = com_ibm_rave_ext_layout_hexbin_Hexbin._hexagon(this.r).slice(0, 4).join("l"); return this.centers().map(function(currentValue, index, array) { var p = currentValue; return "M" + p["x"] + "," + p["y"] + "m" + fragment; }).join(""); }), /** * Sets the available layout size to the specified two-element array of numbers representing x and y. * @param (Array) size An array of two elements representing x and y. * @return (com.ibm.rave.ext.layout.hexbin.Hexbin) this Hexbin instance with the new size. */ size$0 : function(size) { this.width = size[0]; this.height = size[1]; return this; }, /** * Returns the current layout size of the Hexbin. * @return (Array) the current size, which defaults to 1x1. */ size$1 : function() { return [this.width, this.height]; }, /** * Sets the hexagon radius to the specified numeric value. * @param (double) radius The new radius to set. * @return (com.ibm.rave.ext.layout.hexbin.Hexbin) this Hexbin instance with the new radius. */ radius$0 : function(radius) { this.r = radius; this.dx = this.r * 2 * Math.sin(Math.PI / 3); this.dy = this.r * 1.5; return this; }, /** * Returns the current radius, which defaults to 1. * @return (double) this Hexbin instance. */ radius$1 : function() { return this.r; }, /** @expose */ x : function(a0) { var args = arguments; if (args.length == 0) { return this.x$1(); } return this.x$0(a0); }, /** @expose */ y : function(a0) { var args = arguments; if (args.length == 0) { return this.y$1(); } return this.y$0(a0); }, /** @expose */ hexagon : function(a0) { var args = arguments; if (args.length == 0) { return this.hexagon$1(); } return this.hexagon$0(a0); }, /** @expose */ size : function(a0) { var args = arguments; if (args.length == 0) { return this.size$1(); } return this.size$0(a0); }, /** @expose */ radius : function(a0) { var args = arguments; if (args.length == 0) { return this.radius$1(); } return this.radius$0(a0); } }); com_ibm_rave_ext_layout_hexbin_Hexbin._hexagon = function(radius) { return com_ibm_rave_ext_layout_hexbin_Hexbin.rave_hexbinAngles.map(new (rave['internal']['Declare']({ x0 : 0, y0 : 0, _$functionClassMethod : function() { var _$self = function(currentValue, index, array) { var angle = currentValue; var x1 = Math.sin(angle) * radius; var y1 = -Math.cos(angle) * radius; var dx = x1 - _$self.x0; var dy = y1 - _$self.y0; _$self.x0 = x1; _$self.y0 = y1; return [dx, dy]; }; return _$self; } }))()); }; com_ibm_rave_ext_layout_hexbin_Hexbin.rave_hexbinAngles = rave.range(0, 2 * Math.PI, Math.PI / 3); com_ibm_rave_ext_layout_hexbin_Hexbin.hexbinX = function(d, i) { return d[0]; }; com_ibm_rave_ext_layout_hexbin_Hexbin.hexbinY = function(d, i) { return d[1]; }; // $source: com/ibm/rave/ext/layout/cloud/CloudLayout /************************************************************************ ** IBM Confidential ** ** IBM Business Analytics: Rapidly Adaptive Visualization Engine ** ** (C) Copyright IBM Corp. 2020 ** ** The source code for this program is not published or otherwise divested of its trade secrets, ** irrespective of what has been deposited with the U.S. Copyright Office. ************************************************************************/ // GENERATED //@import com/ibm/rave/ext/layout/cloud/nativeImpl/GraphicContextUtil (runtime) // isDocumentDefined /** * Word cloud layout by Jason Davies, http://www.jasondavies.com/word-cloud/ Algorithm due to Jonathan Feinberg, http://static.mrfeinberg.com/bv_ch03.pdf As word placement can be quite slow for more than a few hundred words, the layout algorithm can be run asynchronously, with a configurable time step size. This makes it possible to animate words as they are placed without stuttering. It is recommended to always use a time step even without animations as it prevents the browser's event loop from blocking while placing the words. This is how the layout is configured:
var fontSize = Rave.scale.log().range([10, 100]); var layout = rave.capability.cloud() .size([960, 600]) .timeInterval(10) .text(function(d) { return d.key; }) .font("Impact") .fontSize(function(d) { return fontSize(+d.value); }) .rotate(function(d) { return ~~( Rave.random.random().randomize() * 5) * 30 - 60; }) .padding(1) .on("word", progress) .on("end", draw) .words([...]) .start();
The text, font, fontSize, rotate and padding options all take either constant values or accessor functions that are called for each datum. There are three events: "word", fired each time a word is successfully placed, "step" fired at each time interval(if interval is set), and "end", fired when all words have been placed. To stop a running layout, simply call layout.stop(). For synchronous operation, you can use timeInterval(Infinity).
*/
var com_ibm_rave_ext_layout_cloud_CloudLayout = rave['internal']['Declare']({
//_step : null,
//cbounds : null,
/**
* area extent value (width and height)
*/
//_size : null,
//_text : null,
//_font : null,
//_fontSize : null,
//_fontStyle : null,
//_fontWeight : null,
//_rotate : null,
//_padding : null,
//_spiral : null,
//_words : null,
//_event : null,
//_timer : null,
//_context : null,
//_paddingValue : null,
//_fontWeightValue : null,
//_rotateValue : null,
//_fontStyleValue : null,
//_fontValue : null,
//_fontSizeValue : null,
//_textValue : null,
ci : -1,
ratio : 1,
_timeInterval : Infinity,
constructor : function() {
this._size = [256, 256];
this._text = com_ibm_rave_ext_layout_cloud_CloudLayout.cloudText;
this._font = com_ibm_rave_ext_layout_cloud_CloudLayout.cloudFont;
this._fontSize = com_ibm_rave_ext_layout_cloud_CloudLayout.cloudFontSize;
this._fontStyle = com_ibm_rave_ext_layout_cloud_CloudLayout.cloudFontNormal;
this._fontWeight = com_ibm_rave_ext_layout_cloud_CloudLayout.cloudFontNormal;
this._rotate = com_ibm_rave_ext_layout_cloud_CloudLayout.cloudRotate;
this._padding = com_ibm_rave_ext_layout_cloud_CloudLayout.cloudPadding;
this._spiral = com_ibm_rave_ext_layout_cloud_CloudLayout._archimedeanSpiral();
this._event = rave.dispatch("word", "end", "step");
{
var canvas;
if (com_ibm_rave_ext_layout_cloud_nativeImpl_GraphicContextUtil.isDocumentDefined()) {
canvas = rave.canvas.create(1, 1);
this.ratio = Math.sqrt(canvas.getContext("2d").getImageData(0, 0, 1, 1).data.length >> 2);
canvas["width"] = (64 << 5) / this.ratio;
canvas["height"] = 2048 / this.ratio;
} else {
canvas = rave.canvas.create(64 << 5, 2048);
}
this._context = canvas.getContext("2d");
this._context.fillStyle = this._context.strokeStyle = "red";
this._context.textAlign = "center";
}
},
/**
* Even binding to "end" , "step" or "word" events. There are two events: - "step", fired each time a time interval has elapsed, - "word", fired each time a word is successfully placed, - "end", fired when all words have been placed. The event callback contains the following arguments: - "step" : arg[0] - collection of data nodes, representing words that had been placed, arg[1] - [[x0,y0][x1,y1]] coordinates describing rectangle of the actual bounds used by the layout - "word" : arg[0] - data node, representing the word, which has been placed - "end" : arg[0] - collection of data nodes, representing words that had been placed, arg[1] - [[x0,y0][x1,y1]] coordinates describing rectangle of the actual bounds used by the layout , arg[2] - collection of data nodes, representing words that did not fit (if any), arg[3] - scale required to increase the size to fit all words, e.g. scale of 1.5 means - increase size by 1.5 times to fit all words
* @param (String) type "end" | "word" | "step" event type
* @param (rave['internal']['RunFunction']) listener event listener , which will be notified
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
/** @expose */
on : function(type, listener) {
this._event.on(type, listener);
return this;
},
cloudCollide : function(tag, board, sw) {
var _sw = sw;
_sw >>= 5;
var sprite = tag["sprite"];
var w = ~~tag["width"] >> 5;
var lx = tag["x"] - (w << 4);
var sx = lx & 0x7f;
var msx = 32 - sx;
var h = ~~(tag["y1"] - tag["y0"]);
var x = ~~(tag["y"] + tag["y0"]) * _sw + (lx >> 5);
var last;
for (var j = 0; j < h; ++j) {
last = 0;
for (var i = 0; i <= w; ++i) {
var _board = x + i < board.length ? board[x + i] : 0;
var _sprite = (!sprite || j * w + i >= sprite.length) ? 0 : sprite[j * w + i];
if ((((last << msx) | (i < w ? (last = _sprite) >>> sx : 0)) & _board) != 0) {
return true;
}
}
x += _sw;
}
return false;
},
collideRects : function(a, bounds) {
var test1 = a["x"] + a["x1"] > bounds[0][0];
var test2 = a["x"] + a["x0"] < bounds[1][0];
var test3 = a["y"] + a["y1"] > bounds[0][1];
var test4 = a["y"] + a["y0"] < bounds[1][1];
return test1 && test2 && test3 && test4;
},
/**
* Starts the layout
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
/** @expose */
start : function() {
this.initContext();
var cloud = this;
this.cbounds = null;
this.ci = -1;
var n = this.words().length;
var tags = [];
var data = this.words().map(function(d, i, array) {
d["text"] = cloud._text.call(this, d, i, 0);
if (d["text"] != null && d["text"].length > 50) {
d["text"] = d["text"].substring(0, 50 - 1) + "...";
}
d["font"] = cloud._font.call(this, d, i, 0);
d["style"] = cloud._fontStyle.call(this, d, i, 0);
d["weight"] = cloud._fontWeight.call(this, d, i, 0);
d["rotate"] = cloud._rotate.call(this, d, i, 0);
d["size"] = cloud._fontSize.call(this, d, i, 0);
d["padding"] = cloud._padding.call(this, d, i, 0);
d["width"] = d["height"] = d["x0"] = d["y0"] = d["x1"] = d["y1"] = 0.0;
d["sprite"] = null;
d["x"] = d["y"] = d["xoff"] = d["yoff"] = 0;
return d;
});
this.cloudSprite(data);
data.sort(function(a, b) {
return ~~(Math.max(b["width"], b["height"]) - Math.max(a["width"], a["height"]));
});
var board = com_ibm_rave_ext_layout_cloud_CloudLayout.zeroArray((this._size[0] >> 5) * this._size[1]);
this._step = function() {
if (cloud._size[0] <= 0 || cloud._size[1] <= 0) {
return;
}
var d;
var start = Date.now();
while (Date.now() - start < cloud._timeInterval && ++cloud.ci < n && (cloud._timer != null)) {
d = data[cloud.ci];
d["x"] = (~~(cloud._size[0] * (com_ibm_rave_ext_layout_cloud_CloudLayout.getRandom() + .5))) >> 1;
d["y"] = (~~(cloud._size[1] * (com_ibm_rave_ext_layout_cloud_CloudLayout.getRandom() + .5))) >> 1;
if (d["hasText"] && cloud.place(board, d, cloud.cbounds)) {
tags.push(d);
cloud._event["word"].call(cloud, d);
if (cloud.cbounds) {
com_ibm_rave_ext_layout_cloud_CloudLayout.cloudBounds(cloud.cbounds, d);
} else {
cloud.cbounds = [[d["x"] + d["x0"], d["y"] + d["y0"]], [d["x"] + d["x1"], d["y"] + d["y1"]]];
}
d["x"] -= cloud._size[0] >> 1;
d["y"] -= cloud._size[1] >> 1;
}
}
cloud._event["step"].call(cloud, tags, cloud.cbounds);
if (cloud.ci >= n) {
cloud.stop();
cloud._event["end"].call(cloud, tags, cloud.cbounds);
}
};
if (this._timer != null) {
clearInterval(this._timer);
}
if (cloud._timeInterval != Infinity) {
this._timer = setInterval(this._step, 0);
} else {
this._timer = {};
this._step();
}
return cloud;
},
/**
* loops through all data nodes and creates the sprite for each while calculating the area needed to lay them all out
* @param (Array) data the data nodes
*/
cloudSprite : function(data) {
var area = 0;
var maxHeight = 0;
var maxWidth = 0;
var startIndex = 0;
do {
var index = startIndex;
var maxIndex = index;
this._context.clearRect(0, 0, (64 << 5) / this.ratio, 2048 / this.ratio);
var x = 0;
var y = 0;
var n = data.length;
var maxh = 0;
--index;
while (++index < n) {
var d = data[index];
if (d["sprite"] || d["text"] == null || d["text"].length == 0) {
continue;
}
this._context.save();
this._context.font = d["style"] + " normal " + d["weight"] + " " + ~~((d["size"] + 1) / this.ratio) + "px/normal " + d["font"];
var w = this._context.measureText(d["text"])["width"] * this.ratio;
var h = d["size"] << 1;
if (d["rotate"] != 0) {
var sr = Math.sin(d["rotate"] * 0.017453292519943295);
var cr = Math.cos(d["rotate"] * 0.017453292519943295);
var wcr = w * cr;
var wsr = w * sr;
var hcr = h * cr;
var hsr = h * sr;
w = ((~~(Math.max(Math.abs(wcr + hsr), Math.abs(wcr - hsr)) + 0x1f)) >> 5) << 5;
h = ~~Math.max(Math.abs(wsr + hcr), Math.abs(wsr - hcr));
} else {
w = ((~~w + 0x1f) >> 5) << 5;
}
if (h > maxh) {
maxh = h;
}
if (x + w >= (64 << 5)) {
x = 0;
y += maxh;
maxh = 0;
}
if (y + h >= 2048) {
break;
}
this._context.translate((x + (~~w >> 1)) / this.ratio, (y + (~~h >> 1)) / this.ratio);
if (d["rotate"] != 0) {
this._context.rotate(d["rotate"] * 0.017453292519943295);
}
this._context.fillText(d["text"], 0, 0);
if (d["padding"] != 0) {
this._context.lineWidth = 2 * d["padding"];
this._context.strokeText(d["text"], 0, 0);
}
this._context.restore();
d["width"] = w;
d["height"] = h;
d["xoff"] = x;
d["yoff"] = y;
d["x1"] = ~~w >> 1;
d["y1"] = ~~h >> 1;
d["x0"] = -d["x1"];
d["y0"] = -d["y1"];
d["hasText"] = true;
x += w;
maxWidth = Math.max(maxWidth, w);
maxHeight = Math.max(maxHeight, h);
}
maxIndex = index;
var pixels = this._context.getImageData(0, 0, (64 << 5) / this.ratio, 2048 / this.ratio).data;
var sprite = [];
while (--index >= startIndex) {
var d = data[index];
if (!d["hasText"]) {
continue;
}
var w = d["width"];
var w32 = (~~w) >> 5;
var h = d["y1"] - d["y0"];
for (var i = 0; i < h * w32; ++i) {
sprite[i] = 0;
}
if (d["xoff"] == null) {
startIndex = maxIndex;
break;
}
x = d["xoff"];
y = d["yoff"];
var seen = 0, seenRow = -1;
for (var j = 0; j < h; ++j) {
for (var i = 0; i < w; ++i) {
var k = w32 * j + (i >> 5);
var m = (pixels[((y + j) * (64 << 5) + (x + i)) << 2] != 0) ? 1 << (31 - (i % 32)) : 0;
sprite[k] = sprite[k] | m;
seen |= m;
}
if (seen != 0) {
seenRow = j;
} else {
d["y0"]++;
h--;
j--;
y++;
}
}
d["y1"] = d["y0"] + seenRow;
d["sprite"] = sprite.slice(0, ~~((d["y1"] - d["y0"]) * w32));
area += (d["width"] * d["height"]) * 1.4;
}
startIndex = maxIndex;
} while (startIndex < data.length);
if (this._size[0] > 0 && this._size[1] > 0) {
var newWidth = Math.ceil(this._size[0] * Math.sqrt(+ (area) / (this._size[0] * this._size[1])));
var newHeight = Math.ceil(this._size[1] * Math.sqrt(+ (area) / (this._size[0] * this._size[1])));
if (newWidth > this._size[0] || newHeight > this._size[1]) {
this.size([newWidth, newHeight]);
}
if (maxWidth > this._size[0] || maxHeight > this._size[1]) {
var widthPercent = maxWidth / this._size[0];
var heightPercent = maxHeight / this._size[1];
var increasePercent = Math.max(widthPercent, heightPercent) * 1.4;
if (increasePercent > 1.0) {
this.size([Math.ceil(this._size[0] * increasePercent), Math.ceil(this._size[1] * increasePercent)]);
}
}
}
},
/**
* Stops the layout
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
/** @expose */
stop : function() {
if (this._timer != null) {
clearInterval(this._timer);
this._timer = null;
}
this.disposeContext();
return this;
},
place : function(board, tag, bounds) {
var startX = tag["x"];
var startY = tag["y"];
var maxDelta = Math.sqrt(this._size[0] * this._size[0] + this._size[1] * this._size[1]);
var s = this.__spiral(this._size);
var dt = com_ibm_rave_ext_layout_cloud_CloudLayout.getRandom() < .5 ? 1 : -1, t = -dt;
var dx, dy;
var dxdy;
while ((dxdy = s(t += dt))) {
dx = ~~(dxdy[0]);
dy = ~~(dxdy[1]);
if (Math.min(dx, dy) > maxDelta) {
break;
}
tag["x"] = startX + dx;
tag["y"] = startY + dy;
if (tag["x"] + tag["x0"] < 0 || tag["y"] + tag["y0"] < 0 || tag["x"] + tag["x1"] >= this._size[0] || tag["y"] + tag["y1"] >= this._size[1]) {
continue;
}
if (!bounds || !(this.cloudCollide(tag, board, this._size[0]))) {
if (!bounds || this.collideRects(tag, bounds)) {
var sprite = tag["sprite"];
var w = ~~tag["width"] >> 5, sw = this.size()[0] >> 5, lx = tag["x"] - (w << 4), sx = lx & 0x7f, msx = 32 - sx, h = ~~(tag["y1"] - tag["y0"]), x = ~~(tag["y"] + tag["y0"]) * sw + (lx >> 5), last;
for (var j = 0; j < h; ++j) {
last = 0;
for (var i = 0; i <= w; ++i) {
board[x + i] |= (last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0);
}
x += sw;
}
tag["sprite"] = null;
return true;
}
}
}
return false;
},
/**
* As word placement can be quite slow for more than a few hundred words, the layout algorithm can be run asynchronously, with a configurable time step size. This makes it possible to animate words as they are placed without stuttering Sets step interrupt interval. When set to infinity layout step runs until all the nodes are laid out. Infinity is the default
* @param (Number) x time interval
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
timeInterval$0 : function(x) {
this._timeInterval = x == null ? Infinity : x;
return this;
},
/**
* As word placement can be quite slow for more than a few hundred words, the layout algorithm can be run asynchronously, with a configurable time step size. This makes it possible to animate words as they are placed without stuttering Returns step interrupt interval. When set to infinity layout step runs until all the nodes are laid out. Infinity is the default
* @return (Number) time step interval
*/
timeInterval$1 : function() {
return this._timeInterval;
},
/**
* Sets data array of cloud data nodes
* @param (Array) nodes array of cloud data nodes
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
* @see (Object) CloudDataNode
*/
words$0 : function(nodes) {
this._words = nodes;
return this;
},
/**
* Returns array of data nodes
* @return (Array) array of data nodes
* @see (Object) CloudDataNode
*/
words$1 : function() {
return this._words;
},
/**
* Returns the current size, which defaults to 1x1
* @return (int[]) return the current size
*/
size$0 : function() {
return this._size;
},
/**
* Sets the available layout size to the specified two-element array of numbers representing x and y.
* @param (int[]) newSize the size of the layout
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this Layout
*/
size$1 : function(newSize) {
this._size = newSize;
return this;
},
/**
* Sets font family name same for all data nodes. This is a prioritized list of font family names and/or generic family names. It should be formatted as a comma-separated list and each family name should be single-quoted, for example: "'Roboto', 'Helvetica', 'Arial', 'sans-serif'"
.
* @param (String) value string font family name list
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
font$0 : function(value) {
this._font = function(data, index, groupIndex) {
return value;
};
this._fontValue = value;
return this;
},
/**
* Sets font family name to a function. Function takes data node as a parameter and returns font family name string. Each returned string is a prioritized list of font family names and/or generic family names. It should be formatted as a comma-separated list and each family name should be single-quoted, for example: "'Roboto', 'Helvetica', 'Arial', 'sans-serif'"
.
* @param (rave['internal']['ValueFunction']) value font family name function
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
font$1 : function(value) {
this._font = value;
this._fontValue = null;
return this;
},
/**
* Returns font family value or function.Function takes data node as a parameter and returns font family name string
* @return (Object) font family value or function
*/
font$2 : function() {
return this._fontValue != null ? this._fontValue : this._font;
},
/**
* Returns font style value or function. The function takes cloud data node as a parameter and returns font style value for the given node. Valid font style values are "normal" | "italic" | "oblique"
* @return (Object) font style value or function
*/
fontStyle$0 : function() {
return this._fontStyleValue != null ? this._fontStyleValue : this._fontStyle;
},
/**
* Sets font style for all data nodes to "normal" | "italic" | "oblique"
* @param (String) value font style value as "normal" | "italic" | "oblique"
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
fontStyle$1 : function(value) {
this._fontStyle = function(data, index, groupIndex) {
return value;
};
this._fontStyleValue = value;
return this;
},
/**
* Sets font style function. The function takes cloud data node as a parameter and returns font style value for the given node. Valid font style values are "normal" | "italic" | "oblique"
* @param (rave['internal']['ValueFunction']) fontStyleFn font style function
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
fontStyle$2 : function(fontStyleFn) {
this._fontStyle = fontStyleFn;
this._fontStyleValue = null;
return this;
},
/**
* Returns rotation function or rotation angle in degrees.
* @return (Object) rotation function or rotation angle in degrees
*/
rotate$0 : function() {
return this._rotateValue != null ? this._rotateValue : this._rotate;
},
/**
* Sets rotation angle in degrees for all nodes
* @param (int) value rotation angle in degrees
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
rotate$1 : function(value) {
this._rotate = function(data, index, groupIndex) {
return value;
};
this._rotateValue = value;
return this;
},
/**
* Sets rotation function. The function takes cloud data node as a parameter and returns rotation angle in degrees for the given node
* @param (rave['internal']['ValueFunction']) _rotateFn rotation function
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
rotate$2 : function(_rotateFn) {
this._rotate = _rotateFn;
this._rotateValue = null;
return this;
},
/**
* Returns text function. Function takes cloud data node as a parameter and returns text string for the data node
* @return (Object) text function
*/
text$0 : function() {
return this._textValue != null ? this._textValue : this._text;
},
/**
* Sets the same text string for all data nodes
* @param (String) value text string
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
text$1 : function(value) {
this._text = function(data, index, groupIndex) {
return value;
};
this._textValue = value;
return this;
},
/**
* Set text function. Function takes cloud data node as a parameter and returns text string
* @param (rave['internal']['ValueFunction']) value text function
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
text$2 : function(value) {
this._text = value;
this._textValue = null;
return this;
},
/**
* Return spiral function (e.g. archimedean or rectangular)
* @return (rave['internal']['SingleValueFunction']) current spiral function
*/
spiral$0 : function() {
return this._spiral;
},
/**
* Sets spiral function to either archimedean or rectangular
* @param (String) name "archimedean" or "rectangular"
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
spiral$1 : function(name) {
if (com_ibm_rave_ext_layout_cloud_CloudLayout.ARCHIMEDEAN == name) {
this._spiral = com_ibm_rave_ext_layout_cloud_CloudLayout._archimedeanSpiral();
} else {
this._spiral = com_ibm_rave_ext_layout_cloud_CloudLayout._rectangularSpiral();
}
return this;
},
__spiral : function(arg) {
return this._spiral(arg);
},
/**
* Sets font size function. Function takes cloud data node as a parameter and returns font size for the data node
* @param (rave['internal']['ValueFunction']) fontSizeFn font size function
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
fontSize$0 : function(fontSizeFn) {
this._fontSize = fontSizeFn;
this._fontSizeValue = null;
return this;
},
/**
* Returns font size or font size function. Function takes cloud data node as a parameter and returns font size for the data node
* @return (Object) font size function
*/
fontSize$1 : function() {
return this._fontSizeValue != null ? this._fontSizeValue : this._fontSize;
},
/**
* Sets uniform font size for all data nodes
* @param (Number) value font size for all data nodes
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
fontSize$2 : function(value) {
this._fontSize = function(data, index, groupIndex) {
return value;
};
this._fontSizeValue = + (value);
return this;
},
/**
* Returns padding - a function or integer value
* @return (Object) padding function or integer value
*/
padding$0 : function() {
return this._paddingValue != null ? this._paddingValue : this._padding;
},
/**
* Set padding to an integer value, same for all data nodes
* @param (int) value padding integer value
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
padding$1 : function(value) {
this._padding = function(data, index, groupIndex) {
return value;
};
this._paddingValue = value;
return this;
},
/**
* Sets padding function. The function takes cloud data node as a parameter and returns padding for the given node
* @param (rave['internal']['ValueFunction']) paddingFn padding function
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
padding$2 : function(paddingFn) {
this._padding = paddingFn;
this._paddingValue = null;
return this;
},
/**
* Sets font weight function. The function takes cloud data node as a parameter and returns font weight string for the given node. Font weight string values are "normal" | "bold" | number
* @param (rave['internal']['ValueFunction']) fontWeightFn font weight function
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
fontWeight$0 : function(fontWeightFn) {
this._fontWeight = fontWeightFn;
this._fontWeightValue = null;
return this;
},
/**
* Returns font weight string or function. The function takes cloud data node as a parameter and returns font weight string for the given node. Font weight string values are "normal" | "bold" | number
* @return (Object) font weight - string or function
*/
fontWeight$1 : function() {
return this._fontWeightValue != null ? this._fontWeightValue : this._fontWeight;
},
/**
* Sets font weight for all data nodes. Font weight values are "normal" | "bold" | number
* @param (String) value font weight as "normal" | "bold" | number string
* @return (com.ibm.rave.ext.layout.cloud.CloudLayout) this
*/
fontWeight$2 : function(value) {
this._fontWeight = function(data, index, groupIndex) {
return value;
};
this._fontWeightValue = value;
return this;
},
initContext : function() {
if (!this._context) {
var canvas;
if (com_ibm_rave_ext_layout_cloud_nativeImpl_GraphicContextUtil.isDocumentDefined()) {
canvas = rave.canvas.create(1, 1);
this._context = canvas.getContext("2d");
this.ratio = Math.sqrt(this._context.getImageData(0, 0, 1, 1).data.length >> 2);
rave.canvas.disposeContext(this._context);
this._context = null;
canvas["width"] = (64 << 5) / this.ratio;
canvas["height"] = 2048 / this.ratio;
} else {
canvas = rave.canvas.create(64 << 5, 2048);
}
this._context = canvas.getContext("2d");
this._context.fillStyle = this._context.strokeStyle = "red";
this._context.textAlign = "center";
}
},
disposeContext : function() {
if (this._context) {
rave.canvas.disposeContext(this._context);
this._context = null;
}
},
/** @expose */
timeInterval : function(a0) {
var args = arguments;
if (args.length == 0) {
return this.timeInterval$1();
}
return this.timeInterval$0(a0);
},
/** @expose */
words : function(a0) {
var args = arguments;
if (args.length == 0) {
return this.words$1();
}
return this.words$0(a0);
},
/** @expose */
size : function(a0) {
var args = arguments;
if (args.length == 0) {
return this.size$0();
}
return this.size$1(a0);
},
/** @expose */
font : function(a0) {
var args = arguments;
if (args.length == 0) {
return this.font$2();
}
if (args.length == 1 && (a0 == null || typeof a0 === "string")) {
return this.font$0(a0);
}
return this.font$1(a0);
},
/** @expose */
fontStyle : function(a0) {
var args = arguments;
if (args.length == 0) {
return this.fontStyle$0();
}
if (args.length == 1 && (a0 == null || typeof a0 === "string")) {
return this.fontStyle$1(a0);
}
return this.fontStyle$2(a0);
},
/** @expose */
rotate : function(a0) {
var args = arguments;
if (args.length == 0) {
return this.rotate$0();
}
if (args.length == 1 && typeof a0 === "function") {
return this.rotate$2(a0);
}
return this.rotate$1(a0);
},
/** @expose */
text : function(a0) {
var args = arguments;
if (args.length == 0) {
return this.text$0();
}
if (args.length == 1 && (a0 == null || typeof a0 === "string")) {
return this.text$1(a0);
}
return this.text$2(a0);
},
/** @expose */
spiral : function(a0) {
var args = arguments;
if (args.length == 0) {
return this.spiral$0();
}
return this.spiral$1(a0);
},
/** @expose */
fontSize : function(a0) {
var args = arguments;
if (args.length == 0) {
return this.fontSize$1();
}
if (args.length == 1 && typeof a0 === "function") {
return this.fontSize$0(a0);
}
return this.fontSize$2(a0);
},
/** @expose */
padding : function(a0) {
var args = arguments;
if (args.length == 0) {
return this.padding$0();
}
if (args.length == 1 && typeof a0 === "function") {
return this.padding$2(a0);
}
return this.padding$1(a0);
},
/** @expose */
fontWeight : function(a0) {
var args = arguments;
if (args.length == 0) {
return this.fontWeight$1();
}
if (args.length == 1 && typeof a0 === "function") {
return this.fontWeight$0(a0);
}
return this.fontWeight$2(a0);
}
});
com_ibm_rave_ext_layout_cloud_CloudLayout._archimedeanSpiral = function() {
return function(size) {
var e = size[0] / (size[1] != 0 ? size[1] : 1);
return function(t) {
var _t = t * .1;
var a = e * _t * Math.cos(_t);
var b = _t * Math.sin(_t);
var result = [a, b];
return result;
};
};
};
com_ibm_rave_ext_layout_cloud_CloudLayout._rectangularSpiral = function() {
return function(size) {
var x = 0, y = 0;
var dy = 4, dx = dy * size[0] / size[1];
return function(t) {
var sign = t < 0 ? -1 : 1;
switch ((~~(Math.sqrt(1 + 4 * sign * t) - sign)) & 3) {
case 0:
x += dx;
break;
case 1:
y += dy;
break;
case 2:
x -= dx;
break;
default:
y -= dy;
break;
}
var result = [x, y];
return result;
};
};
};
com_ibm_rave_ext_layout_cloud_CloudLayout.zeroArray = function(n) {
var a = [];
for (var i = 0; i < n; ++i) {
a[i] = 0;
}
return a;
};
com_ibm_rave_ext_layout_cloud_CloudLayout.cloudBounds = function(bounds, d) {
var b0 = bounds[0], b1 = bounds[1];
if (d["x"] + d["x0"] < b0[0]) {
b0[0] = d["x"] + d["x0"];
}
if (d["y"] + d["y0"] < b0[1]) {
b0[1] = d["y"] + d["y0"];
}
if (d["x"] + d["x1"] > b1[0]) {
b1[0] = d["x"] + d["x1"];
}
if (d["y"] + d["y1"] > b1[1]) {
b1[1] = d["y"] + d["y1"];
}
};
com_ibm_rave_ext_layout_cloud_CloudLayout.getRandom = function() {
return rave.random.randomizer()();
};
com_ibm_rave_ext_layout_cloud_CloudLayout.BUFFER_INCREASE_PERCENT = 1.4;
com_ibm_rave_ext_layout_cloud_CloudLayout.WORD_LETTER_MAX_LENGTH = 50;
com_ibm_rave_ext_layout_cloud_CloudLayout.ARCHIMEDEAN = "archimedean";
com_ibm_rave_ext_layout_cloud_CloudLayout.cloudText = function(data, index, groupIndex) {
return (data)["text"];
};
com_ibm_rave_ext_layout_cloud_CloudLayout.cloudFont = function(data, index, groupIndex) {
return "serif";
};
com_ibm_rave_ext_layout_cloud_CloudLayout.cloudFontNormal = function(data, index, groupIndex) {
return "normal";
};
com_ibm_rave_ext_layout_cloud_CloudLayout.cloudFontSize = function(data, index, groupIndex) {
return Math.sqrt((data)["value"]);
};
com_ibm_rave_ext_layout_cloud_CloudLayout.cloudRotate = function(data, index, groupIndex) {
return ((~~(com_ibm_rave_ext_layout_cloud_CloudLayout.getRandom() * 6)) - 3) * 30;
};
com_ibm_rave_ext_layout_cloud_CloudLayout.cloudPadding = function(data, index, groupIndex) {
return 1;
};
com_ibm_rave_ext_layout_cloud_CloudLayout.cloudRadians = Math.PI / 180;
com_ibm_rave_ext_layout_cloud_CloudLayout.context_width = (1 << 11) >> 5;
com_ibm_rave_ext_layout_cloud_CloudLayout.context_height = 1 << 11;
// $source: com/ibm/rave/ext/layout/cloud/nativeImpl/GraphicContextUtil
/************************************************************************
** IBM Confidential
**
** IBM Business Analytics: Rapidly Adaptive Visualization Engine
**
** (C) Copyright IBM Corp. 2015
**
** The source code for this program is not published or otherwise divested of its trade secrets,
** irrespective of what has been deposited with the U.S. Copyright Office.
************************************************************************/
/** @expose */
var com_ibm_rave_ext_layout_cloud_nativeImpl_GraphicContextUtil = {
isDocumentDefined : function(){
return typeof document !== "undefined";
}
};
// $source: com/ibm/rave/ext/internal/layout/bubble/CirclePackMethod
/************************************************************************
** IBM Confidential
**
** IBM Business Analytics: Rapidly Adaptive Visualization Engine
**
** (C) Copyright IBM Corp. 2017
**
** The source code for this program is not published or otherwise divested of its trade secrets,
** irrespective of what has been deposited with the U.S. Copyright Office.
************************************************************************/
// GENERATED
//@import com/ibm/rave/ext/internal/layout/bubble/BubblePackLayoutMethod (loadtime) // distance, superclass
//@import com/ibm/rave/ext/internal/layout/utils/Qtree (runtime) // newQTreeNode, new
//@import com/ibm/rave/ext/internal/layout/utils/DoubleUtils (runtime) // compare
/**
* Algorithm, which will pack all bubbles into a circle
*/
var com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod = rave['internal']['Declare'](com_ibm_rave_ext_internal_layout_bubble_BubblePackLayoutMethod, {
/**
* interm values used by algorithm
*/
//radii : null,
//extent : null,
//edges : null,
//locations : null,
//tree : null,
//collision_test : null,
/**
* Constructor
* @param (Array) extent - available area extent
*/
constructor : function(extent) {
this.extent = extent;
},
getLocationForCanonicalCircles : function(r, r0, r1, p) {
var A = r0 + r1;
var B = r0 + r;
var C = r1 + r;
var x = (A * A + B * B - C * C) / 2 / A;
var y = Math.sqrt(B * B - x * x);
if (!p) {
return [x, y];
}
p[0] = x;
p[1] = y;
return p;
},
_createRootNode : function(node) {
var root = {};
root["item"] = null;
this._updateRectangle(root, [node["x"], node["y"]], node["r"]);
return root;
},
_createQTNode : function(index) {
var node = {};
node["item"] = index;
this._updateRectangle(node, this.locations[index], this.radii[index]);
return node;
},
_updateRectangle : function(node, point, r) {
var size = 2 * r;
node["x"] = point[0] - r;
node["y"] = point[1] - r;
node["width"] = size;
node["height"] = size;
},
pack : function(root) {
var nodes = root["children"];
if (!nodes || nodes.length == 0) {
return;
}
var n = nodes.length;
this.radii = [];
var reverseOrder = [];
this.edges = [];
var o = com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod.makeSortOrder(nodes);
for (var i = 0; i < n; ++i) {
var idx = o[n - i - 1];
reverseOrder[idx] = i;
var child = nodes[idx];
this.radii[i] = child["r"];
}
this.locations = [];
this.tree = new com_ibm_rave_ext_internal_layout_utils_Qtree(0, this._createRootNode(root));
this.collision_test = com_ibm_rave_ext_internal_layout_utils_Qtree.newQTreeNode(0, 0, 0, 0, null);
this.locations[0] = [0, 0];
if (n > 1) {
var d = this.radii[0] + this.radii[1];
this.locations[1] = [d, 0];
}
if (n > 2) {
var r0 = this.radii[0];
var r1 = this.radii[1];
var r2 = this.radii[2];
var q = this.getLocationForCanonicalCircles(r2, r0, r1, null);
this.locations[2] = q;
var w = r0 * r0 + r1 * r1 + r2 * r2;
var sx = r1 * r1 * (r1 + r0) + r2 * r2 * q[0];
var sy = r2 * r2 * q[1];
for (var i = 0; i < 3; ++i) {
this.locations[i][0] = this.locations[i][0] - sx / w;
this.locations[i][1] = this.locations[i][1] - sy / w;
}
this.addEdge(new com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod.BubbleEdgeData(0, 1));
this.addEdge(new com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod.BubbleEdgeData(1, 0));
this.addEdge(new com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod.BubbleEdgeData(0, 2));
this.addEdge(new com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod.BubbleEdgeData(2, 0));
this.addEdge(new com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod.BubbleEdgeData(1, 2));
this.addEdge(new com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod.BubbleEdgeData(2, 1));
}
for (var i = 0, p = ~~Math.min(3, n); i < p; ++i) {
this.tree.insert(this._createQTNode(i));
}
if (n > 3) {
for (var k = 3; k < n; ++k) {
this.placeOnEdge(k);
}
}
var minMax = new rave['internal']['XYMin_Max']();
for (var i = 0; i < n; ++i) {
var location = this.locations[reverseOrder[i]];
var node = nodes[i];
node["x"] = location[0];
node["y"] = location[1];
minMax.bound(node);
}
var cx = (minMax.xMin + minMax.xMax) / 2, cy = (minMax.yMin + minMax.yMax) / 2, cr = 0;
for (var i = 0; i < n; ++i) {
var node = nodes[i];
node["x"] -= cx;
node["y"] -= cy;
cr = Math.max(cr, node["r"] + Math.sqrt(node["x"] * node["x"] + node["y"] * node["y"]));
}
root["r"] = cr;
},
placeOnEdge : function(k) {
var r = this.radii[k];
var q = [0, 0];
for (var i = 0; i < this.edges.length; ++i) {
var edge = this.edges[i];
var cr = edge.cr;
var isCrSet = cr != -1;
if (!isCrSet || r <= cr) {
var e1 = edge.e1;
var e2 = edge.e2;
this.placeTouching(this.locations[e1], this.radii[e1], this.locations[e2], this.radii[e2], r, q);
var intersects;
if (isCrSet) {
intersects = false;
} else if (edge.nearShapes) {
intersects = this.intersectsNearShapes(q, r, edge);
} else {
intersects = this.intersectsExisting(q, r, k);
}
if (!intersects) {
this.locations[k] = q;
this.tree.insert(this._createQTNode(k));
edge.cr = com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod.getLargestInsideCircleRadius(r, this.radii[e1], this.radii[e2]);
var bed1 = new com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod.BubbleEdgeData(k, e2);
var bed2 = new com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod.BubbleEdgeData(e1, k);
this.addEdge(bed1);
this.addEdge(bed2);
if (edge.nearShapes) {
bed1.nearShapes = edge.nearShapes;
bed2.nearShapes = edge.nearShapes;
edge.nearShapes.push(k);
} else if (!edge.nearShapes && isCrSet) {
bed1.nearShapes = [];
bed1.nearShapes.push(k);
bed1.nearShapes.push(e1);
bed1.nearShapes.push(e2);
bed1.nearShapes.push(edge.e3);
bed2.nearShapes = bed1.nearShapes;
}
edge.e3 = k;
return;
}
}
}
},
/**
* Check if the circle with radius 'r' at location 'p' intersects with any other circle.
* @param (Array) p - the location of the circle
* @param (double) r - the radius of the circle
* @param (int) n - the number of circles already in the graph
* @return (boolean) true
if the circle would intersect another, false
otherwise
*/
intersectsExisting : function(p, r, n) {
this._updateRectangle(this.collision_test, p, r);
var method = this;
var tester = function(node) {
var rt = r + method.radii[node["item"]] - 1e-2;
var p2 = method.locations[node["item"]];
return com_ibm_rave_ext_internal_layout_bubble_BubblePackLayoutMethod.distance(p, p2) < rt;
};
return this.tree.collide(tester, this.collision_test);
},
placeTouching : function(c0, r0, c1, r1, r, point) {
var x1 = c1[0] - c0[0];
var y1 = c1[1] - c0[1];
var R = r0 + r1;
var cosA = x1 / R;
var sinA = y1 / R;
var p = this.getLocationForCanonicalCircles(r, r0, r1, point);
var x = p[0] * cosA - p[1] * sinA + c0[0];
var y = p[0] * sinA + p[1] * cosA + c0[1];
p[0] = x;
p[1] = y;
return p;
},
/**
* Check if the circle with radius 'r' at location 'p' intersects with any other circle. Only considers the near shapes in the edge data.
* @param (Array) p the location of the circle
* @param (double) r the radius of the circle
* @param (com.ibm.rave.ext.internal.layout.bubble.CirclePackMethod.BubbleEdgeData) edgeData the edge data containing near shapes to consider for intersection
* @return (boolean) true
if the circle would intersect another, false
otherwise
*/
intersectsNearShapes : function(p, r, edgeData) {
var nearShapes = edgeData.nearShapes;
var adjacent1 = edgeData.e1;
var adjacent2 = edgeData.e2;
for (var j = 0, len = nearShapes.length; j < len; ++j) {
var i = nearShapes[j];
if (i != adjacent1 && i != adjacent2) {
var rt = r + this.radii[i] - 1e-2;
var p2 = this.locations[i];
if (com_ibm_rave_ext_internal_layout_bubble_BubblePackLayoutMethod.distance(p, p2) < rt) {
return true;
}
}
}
return false;
},
addEdge : function(e) {
var dp = this.getTouchPointDistance(e);
e.touchPointDistance = dp;
var size = this.edges.length;
if (size == 0) {
this.edges.push(e);
return;
}
var a = 0;
if (dp < this.edges[a].touchPointDistance) {
this.edges.splice(0, 0, e);
return;
}
var b = size - 1;
if (dp >= this.edges[b].touchPointDistance) {
this.edges.push(e);
return;
}
while (b > a + 1) {
var c = Math.floor((a + b) / 2);
var dc = this.edges[c].touchPointDistance;
if (dp < dc) {
b = c;
} else {
a = c;
}
}
this.edges.splice(b, 0, e);
},
getTouchPointDistance : function(e) {
var a = this.locations[e.e1];
var b = this.locations[e.e2];
var ra = this.radii[e.e1];
var rb = this.radii[e.e2];
var x = (a[0] * rb + b[0] * ra) / (ra + rb);
var y = (a[1] * rb + b[1] * ra) / (ra + rb);
return x * x + y * y;
}
});
com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod.makeSortOrder = function(nodes) {
var size = nodes.length;
var result = new Array(size);
for (var i = 0; i < size; ++i) {
result[i] = i;
}
result.sort(function(a, b) {
var indexA = ~~ (a);
var indexB = ~~ (b);
var d1 = nodes[indexA]["r"], d2 = nodes[indexB]["r"];
return com_ibm_rave_ext_internal_layout_utils_DoubleUtils.compare(d1, d2);
});
return result;
};
/**
* Find the largest circle radius that can fit between three other circles using Descartes' theorem.
* @param (double) r1 - first circle radius
* @param (double) r2 - second circle radius
* @param (double) r3 - third circle radius
* @return (double) the inside circle radius
*/
com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod.getLargestInsideCircleRadius = function(r1, r2, r3) {
var a = 1 / r1;
var b = 1 / r2;
var c = 1 / r3;
return 1 / (a + b + c + 2 * Math.sqrt(a * b + b * c + c * a));
};
com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod.BubbleEdgeData = rave['internal']['Declare']({
//nearShapes : null,
e1 : 0,
e2 : 0,
e3 : -1,
cr : -1,
touchPointDistance : 0,
constructor : function(e1, e2) {
this.e1 = e1;
this.e2 = e2;
}
});
// $source: com/ibm/rave/ext/internal/layout/bubble/SquarePackMethod
/************************************************************************
** IBM Confidential
**
** IBM Business Analytics: Rapidly Adaptive Visualization Engine
**
** (C) Copyright IBM Corp. 2017
**
** The source code for this program is not published or otherwise divested of its trade secrets,
** irrespective of what has been deposited with the U.S. Copyright Office.
************************************************************************/
// GENERATED
//@import com/ibm/rave/ext/internal/layout/bubble/CirclePackMethod (loadtime) // superclass
/**
* Algorithm, which will pack all bubbles into a square
*/
var com_ibm_rave_ext_internal_layout_bubble_SquarePackMethod = rave['internal']['Declare'](com_ibm_rave_ext_internal_layout_bubble_CirclePackMethod, {
getTouchPointDistance : function(e) {
var a = this.locations[e.e1];
var b = this.locations[e.e2];
var ra = this.radii[e.e1];
var rb = this.radii[e.e2];
var x = (a[0] * rb + b[0] * ra) / (ra + rb);
var y = (a[1] * rb + b[1] * ra) / (ra + rb);
var dx = Math.abs(x) / this.extent[0];
var dy = Math.abs(y) / this.extent[1];
return Math.max(dx, dy);
}
/**
* Constructor
* @param (Array) extent - available area extent
*/
//constructor : function(extent) {}
});
// $source: com/ibm/rave/ext/layout/RaveLayout
/************************************************************************
** IBM Confidential
**
** IBM Business Analytics: Rapidly Adaptive Visualization Engine
**
** (C) Copyright IBM Corp. 2017
**
** The source code for this program is not published or otherwise divested of its trade secrets,
** irrespective of what has been deposited with the U.S. Copyright Office.
************************************************************************/
// GENERATED
//@import com/ibm/rave/ext/layout/bubble/BubbleLayout (static) // new
//@import com/ibm/rave/ext/layout/fill/FillLayout (static) // new
//@import com/ibm/rave/ext/layout/hexbin/Hexbin (static) // new
//@import com/ibm/rave/ext/layout/cloud/CloudLayout (static) // new
/**
* A factory of extended layouts for rave capability.
* @see BubbleLayout
*/
var com_ibm_rave_ext_layout_RaveLayout = {
};
/**
* @return (com.ibm.rave.ext.layout.bubble.BubbleLayout) a new instance of {@link BubbleLayout}
* @see BubbleLayout
*/
/** @expose */
com_ibm_rave_ext_layout_RaveLayout.bubble = function() {
return new com_ibm_rave_ext_layout_bubble_BubbleLayout();
};
/**
* @return (com.ibm.rave.ext.layout.fill.FillLayout) a new instance of {@link FillLayout}
* @see BubbleLayout
*/
/** @expose */
com_ibm_rave_ext_layout_RaveLayout.fill = function() {
return new com_ibm_rave_ext_layout_fill_FillLayout();
};
/**
* @return (com.ibm.rave.ext.layout.hexbin.Hexbin) a new instance of {@link Hexbin}
* @see Hexbin
*/
/** @expose */
com_ibm_rave_ext_layout_RaveLayout.hexbin = function() {
return new com_ibm_rave_ext_layout_hexbin_Hexbin();
};
/**
*/
/** @expose */
com_ibm_rave_ext_layout_RaveLayout.cloud = function() {
return new com_ibm_rave_ext_layout_cloud_CloudLayout();
};
com_ibm_rave_ext_layout_RaveLayout.getRegistrationStatus = function() {
var registrationStatus = rave['internal']['RaveContextManager'].INSTANCE.getRaveContext().getData("RAVELAYOUT_EXTENSION_REGISTRATION_STATUS_KEY");
if (!registrationStatus) {
registrationStatus = new com_ibm_rave_ext_layout_RaveLayout.RegistrationStatus();
rave['internal']['RaveContextManager'].INSTANCE.getRaveContext().putData("RAVELAYOUT_EXTENSION_REGISTRATION_STATUS_KEY", registrationStatus);
}
return registrationStatus;
};
/**
* Register all extended layouts
* @return (boolean) true if registration was successful, false otherwise
* @see AbstractRegistryService
*/
/** @expose */
com_ibm_rave_ext_layout_RaveLayout.init = function() {
var registrationStatus = com_ibm_rave_ext_layout_RaveLayout.getRegistrationStatus();
if (!registrationStatus.registered) {
registrationStatus.registered = rave.layout.extension("bubble", function() {
return com_ibm_rave_ext_layout_RaveLayout.bubble();
});
registrationStatus.registered &= rave.layout.extension("fill", function() {
return com_ibm_rave_ext_layout_RaveLayout.fill();
});
registrationStatus.registered &= rave.layout.extension("hexbin", function() {
return com_ibm_rave_ext_layout_RaveLayout.hexbin();
});
registrationStatus.registered &= rave.layout.extension("cloud", function() {
return com_ibm_rave_ext_layout_RaveLayout.cloud();
});
}
return registrationStatus.registered;
};
com_ibm_rave_ext_layout_RaveLayout.RegistrationStatus = rave['internal']['Declare']({
registered : false
});
/**
* bubble layout id
*/
/** @expose */
com_ibm_rave_ext_layout_RaveLayout.BUBBLE = "bubble";
/**
* pack layout id
*/
/** @expose */
com_ibm_rave_ext_layout_RaveLayout.FILL = "fill";
/**
* pack layout id
*/
/** @expose */
com_ibm_rave_ext_layout_RaveLayout.CLOUD = "cloud";
/**
* hexbin layout id
*/
/** @expose */
com_ibm_rave_ext_layout_RaveLayout.HEXBIN = "hexbin";
//com_ibm_rave_ext_layout_RaveLayout.EXTENSION_REGISTRATION_STATUS_KEY = "RAVELAYOUT_EXTENSION_REGISTRATION_STATUS_KEY";
// Auto initialization
com_ibm_rave_ext_layout_RaveLayout.init();
if (!rave.layout["bubble"]) {
rave.layout["bubble"] = function() {
return com_ibm_rave_ext_layout_RaveLayout.bubble();
};
} else {
console.log("Could not register extension: RaveLayout");
}
if (!rave.layout["fill"]) {
rave.layout["fill"] = function() {
return com_ibm_rave_ext_layout_RaveLayout.fill();
};
} else {
console.log("Could not register extension: RaveLayout");
}
if (!rave.layout["hexbin"]) {
rave.layout["hexbin"] = function() {
return com_ibm_rave_ext_layout_RaveLayout.hexbin();
};
} else {
console.log("Could not register extension: RaveLayout");
}
if (!rave.layout["cloud"]) {
rave.layout["cloud"] = function() {
return com_ibm_rave_ext_layout_RaveLayout.cloud();
};
} else {
console.log("Could not register extension: RaveLayout");
}
// $source: com/ibm/rave/ext/internal/layout/nativeImpl/Module
/************************************************************************
** IBM Confidential
**
** IBM Business Analytics: Rapidly Adaptive Visualization Engine
**
** (C) Copyright IBM Corp. 2015
**
** The source code for this program is not published or otherwise divested of its trade secrets,
** irrespective of what has been deposited with the U.S. Copyright Office.
************************************************************************/
// @OnDemandLoad("rave-layouts")
// Must be the first import
// @import ./ModuleHeader
// @import com/ibm/rave/ext/layout/RaveLayout
})();
// This is the end of the factory method defined in the header. Added only during a full compiled JS build.
return rave;
}));