basicprimitives
Version:
Basic Primitives Diagrams for JavaScript - data visualization components library that implements organizational chart and multi-parent dependency diagrams, contains implementations of JavaScript Controls and PDF rendering plugins.
264 lines (222 loc) • 9.14 kB
JavaScript
import Rect from '../../../graphics/structs/Rect';
import { VerticalAlignmentType, Visibility, GroupByType, AdviserPlacementType } from '../../../enums';
import TreeItemPosition from '../../../models/TreeItemPosition';
export default function MatrixLayout(items, hideParentConnection, hideChildrenConnection) {
this.items = items;
this.hideParentConnection = hideParentConnection;
this.hideChildrenConnection = hideChildrenConnection;
this.data = {
columns: [],
rows: []
};
};
MatrixLayout.prototype.loop = function (thisArg, onItem) {
if(onItem != null) {
for(var index = 0, len = this.items.length; index < len; index+=1) {
var item = this.items[index];
onItem.call(thisArg, item, 0);
}
}
};
MatrixLayout.prototype.Column = function () {
this.depth = 0;
this.offset = 0;
this.leftPadding = 0;
this.rightPadding = 0;
this.layoutDirection = AdviserPlacementType.Left;
};
MatrixLayout.prototype.Row = function () {
this.depth = 0;
this.offset = 0;
this.horizontalConnectorsDepth = 0;
this.minimalDepth = null;
this.dotsDepth = null;
};
MatrixLayout.prototype.getMatrixWidth = function (maximumColumnsInMatrix, len) {
return Math.min(maximumColumnsInMatrix, Math.ceil(Math.sqrt(len)));
};
MatrixLayout.prototype.measure = function (levelVisibility, isCursor, isSelected, treeItemTemplate, treeItemsPositions, options) {
var data = {
columns: [],
rows: []
};
this.measureColumns(data, this.items, treeItemsPositions, options);
this.measureRows(data, this.items, treeItemsPositions, options);
this.data = data;
var treeItemPosition = new TreeItemPosition();
treeItemPosition.actualVisibility = Visibility.Normal;
treeItemPosition.actualSize = this.getLayoutSize(data);
return treeItemPosition;
};
MatrixLayout.prototype.measureColumns = function (data, items, treeItemsPositions, options) {
var column,
index, len,
maximumColumns = this.getMatrixWidth(options.maximumColumnsInMatrix, items.length);
for (index = 0, len = items.length; index < len; index += 1) {
var treeItem = items[index];
var treeItemId = treeItem.id;
var treeItemPosition = treeItemsPositions[treeItemId];
var horizontalPadding = options.intervals[treeItemPosition.actualVisibility] / 2;
var columnIndex = index % maximumColumns;
column = data.columns[columnIndex];
if (column == null) {
column = new this.Column();
column.layoutDirection = columnIndex % 2 ? AdviserPlacementType.Right : AdviserPlacementType.Left;
data.columns[columnIndex] = column;
}
var itemWidth = horizontalPadding + treeItemPosition.actualSize.width + horizontalPadding;
column.depth = Math.max(column.depth, itemWidth);
}
var arrowTipLength = options.linesWidth * 8;
var offset = 0;
for (index = 0, len = data.columns.length; index < len; index += 1) {
column = data.columns[index];
if (index % 2 == 0) {
switch (options.arrowsDirection) {
case GroupByType.Parents:
column.leftPadding = this.hideChildrenConnection ? 0 : arrowTipLength;
column.rightPadding = 0;
break;
case GroupByType.Children:
column.leftPadding = 0;
column.rightPadding = this.hideParentConnection ? 0 : arrowTipLength;
break;
}
} else {
switch (options.arrowsDirection) {
case GroupByType.Parents:
column.leftPadding = 0;
column.rightPadding = this.hideChildrenConnection ? 0 : arrowTipLength;
break;
case GroupByType.Children:
column.leftPadding = this.hideParentConnection ? 0 : arrowTipLength;
column.rightPadding = 0;
break;
}
}
column.offset = offset + column.leftPadding + column.depth / 2;
offset = column.offset + column.depth / 2 + column.rightPadding;
}
};
MatrixLayout.prototype.measureRows = function (data, items, treeItemsPositions, options) {
var index, len,
row,
maximumColumns = this.getMatrixWidth(options.maximumColumnsInMatrix, items.length);
for (index = 0, len = items.length; index < len; index += 1) {
var treeItem = items[index];
var treeItemId = treeItem.id;
var treeItemPosition = treeItemsPositions[treeItemId];
var rowIndex = Math.floor(index / maximumColumns);
var verticalPadding = options.shifts[treeItemPosition.actualVisibility] / 2;
row = data.rows[rowIndex];
if (row == null) {
row = new this.Row();
data.rows[rowIndex] = row;
}
row.depth = Math.max(row.depth, verticalPadding + treeItemPosition.actualSize.height + verticalPadding);
switch (treeItemPosition.actualVisibility) {
case Visibility.Dot:
case Visibility.Line:
case Visibility.Invisible:
row.dotsDepth = !row.dotsDepth ? treeItemPosition.actualSize.height : Math.min(row.dotsDepth, treeItemPosition.actualSize.height);
break;
default:
row.minimalDepth = !row.minimalDepth ? treeItemPosition.actualSize.height : Math.min(row.minimalDepth, treeItemPosition.actualSize.height);
break;
}
}
var offset = 0;
for (index = 0, len = data.rows.length; index < len; index += 1) {
row = data.rows[index];
row.offset = offset + row.depth / 2;
offset = row.offset + row.depth / 2;
if (row.minimalDepth == null) {
row.minimalDepth = row.depth;
}
if (row.dotsDepth != null && row.dotsDepth > row.minimalDepth) {
row.minimalDepth = row.dotsDepth;
}
switch (options.verticalAlignment) {
case VerticalAlignmentType.Top:
row.horizontalConnectorsDepth = row.minimalDepth / 2.0;
break;
case VerticalAlignmentType.Middle:
row.horizontalConnectorsDepth = row.depth / 2.0;
break;
case VerticalAlignmentType.Bottom:
row.horizontalConnectorsDepth = row.depth - row.minimalDepth / 2.0;
break;
}
}
};
MatrixLayout.prototype.getLayoutSize = function (data) {
return new Rect(0, 0, Math.round(this.getLayoutWidth(data)), Math.round(this.getLayoutHeight(data)));
};
MatrixLayout.prototype.getLayoutWidth = function (data) {
var result = 0,
length = data.columns.length;
if (length > 0) {
var lastColumn = data.columns[length - 1];
result = lastColumn.offset + lastColumn.depth / 2 + lastColumn.rightPadding;
}
return result;
};
MatrixLayout.prototype.getLayoutHeight = function (data) {
var result = 0,
length = data.rows.length;
if (length > 0) {
var lastRow = data.rows[length - 1];
result = lastRow.offset + lastRow.depth / 2;
}
return result;
};
MatrixLayout.prototype.arrange = function (thisArg, parentPosition, layoutDirection, treeItemsPositions, options, onItemPositioned) {
if (onItemPositioned != null) {
var maximumColumns = this.getMatrixWidth(options.maximumColumnsInMatrix, this.items.length);
for (var index = 0, len = this.items.length; index < len; index += 1) {
var treeItem = this.items[index],
treeItemId = treeItem.id;
var columnIndex = index % maximumColumns;
var column = this.data.columns[columnIndex];
var rowIndex = Math.floor(index / maximumColumns);
var row = this.data.rows[rowIndex];
var treeItemPosition = treeItemsPositions[treeItemId];
var actualPosition = this.getItemPosition(treeItemPosition.actualVisibility, column, row, treeItemPosition.actualSize, options.verticalAlignment);
actualPosition.translate(parentPosition.x, parentPosition.y);
treeItemPosition = {
...treeItemPosition,
actualPosition,
horizontalConnectorsShift: parentPosition.y + row.offset - row.depth / 2 + row.horizontalConnectorsDepth,
leftMedianOffset: column.depth / 2 + column.leftPadding,
rightMedianOffset: column.depth / 2 + column.rightPadding,
topConnectorShift: row.depth / 2,
bottomConnectorShift: row.depth / 2
};
onItemPositioned.call(thisArg, treeItemId, treeItemPosition, column.layoutDirection);
}
}
};
MatrixLayout.prototype.getItemPosition = function (visibility, column, row, size, verticalAlignment) {
var itemShift = 0;
switch (visibility) {
case Visibility.Normal:
switch (verticalAlignment) {
case VerticalAlignmentType.Top:
itemShift = 0;
break;
case VerticalAlignmentType.Middle:
itemShift = (row.depth - size.height) / 2.0;
break;
case VerticalAlignmentType.Bottom:
itemShift = row.depth - size.height;
break;
}
break;
case Visibility.Dot:
case Visibility.Line:
case Visibility.Invisible:
itemShift = row.horizontalConnectorsDepth - size.height / 2.0;
break;
}
return new Rect(column.offset - size.width / 2, row.offset - row.depth / 2 + itemShift, size.width, size.height);
};