Migrate layout classes Ts

This commit is contained in:
Paulo Gustavo Veiga 2023-02-10 19:07:21 -08:00
parent c0068b4fee
commit 036cf40f0c
8 changed files with 68 additions and 61 deletions

View File

@ -67,7 +67,7 @@ class DragTopic {
const cy = Math.ceil(y - size.height / 2); const cy = Math.ceil(y - size.height / 2);
this._elem2d.setPosition(cx, cy); this._elem2d.setPosition(cx, cy);
// In case is not free, pivot must be draw ... // In case is not free, pivot must be drawn ...
if (this.isConnected()) { if (this.isConnected()) {
const parent = this.getConnectedToTopic(); const parent = this.getConnectedToTopic();
const predict = this._layoutManager.predict( const predict = this._layoutManager.predict(

View File

@ -1044,7 +1044,6 @@ abstract class Topic extends NodeGraph {
const connector = targetTopic.getShrinkConnector(); const connector = targetTopic.getShrinkConnector();
if (connector) { if (connector) {
connector.setVisibility(false); connector.setVisibility(false);
targetTopic.setChildrenShrunken(true);
} }
} }

View File

@ -24,21 +24,25 @@ import RootedTreeSet from './RootedTreeSet';
abstract class AbstractBasicSorter extends ChildrenSorterStrategy { abstract class AbstractBasicSorter extends ChildrenSorterStrategy {
private INTERNODE_VERTICAL_PADDING = 5; private INTERNODE_VERTICAL_PADDING = 5;
computeChildrenIdByHeights(treeSet: RootedTreeSet, node: Node) { computeChildrenIdByHeights(treeSet: RootedTreeSet, node: Node): Map<number, number> {
const result = {}; const result = new Map<number, number>();
this._computeChildrenHeight(treeSet, node, result); this._computeChildrenHeight(treeSet, node, result);
return result; return result;
} }
protected _getVerticalPadding() { getVerticalPadding(): number {
return this.INTERNODE_VERTICAL_PADDING; return this.INTERNODE_VERTICAL_PADDING;
} }
protected _computeChildrenHeight(treeSet: RootedTreeSet, node: Node, heightCache?) { _computeChildrenHeight(
treeSet: RootedTreeSet,
node: Node,
heightCache?: Map<number, number>,
): number {
// 2* Top and down padding; // 2* Top and down padding;
const height = node.getSize().height + this._getVerticalPadding() * 2; const height = node.getSize().height + this.getVerticalPadding() * 2;
let result; let result: number;
const children = treeSet.getChildren(node); const children = treeSet.getChildren(node);
if (children.length === 0 || node.areChildrenShrunken()) { if (children.length === 0 || node.areChildrenShrunken()) {
result = height; result = height;
@ -53,8 +57,7 @@ abstract class AbstractBasicSorter extends ChildrenSorterStrategy {
} }
if (heightCache) { if (heightCache) {
// eslint-disable-next-line no-param-reassign heightCache.set(node.getId(), result);
heightCache[node.getId()] = result;
} }
return result; return result;

View File

@ -233,13 +233,13 @@ class BalancedSorter extends AbstractBasicSorter {
return 'Balanced Sorter'; return 'Balanced Sorter';
} }
protected _getChildrenForOrder(parent: Node, graph: RootedTreeSet, order: number): Node[] { _getChildrenForOrder(parent: Node, graph: RootedTreeSet, order: number): Node[] {
return this._getSortedChildren(graph, parent).filter( return this._getSortedChildren(graph, parent).filter(
(child) => child.getOrder() % 2 === order % 2, (child) => child.getOrder() % 2 === order % 2,
); );
} }
protected _getVerticalPadding(): number { getVerticalPadding(): number {
return BalancedSorter.INTERNODE_VERTICAL_PADDING; return BalancedSorter.INTERNODE_VERTICAL_PADDING;
} }
} }

View File

@ -20,7 +20,7 @@ import Node from './Node';
import PositionType from '../PositionType'; import PositionType from '../PositionType';
abstract class ChildrenSorterStrategy { abstract class ChildrenSorterStrategy {
abstract computeChildrenIdByHeights(treeSet: RootedTreeSet, node: Node): void; abstract computeChildrenIdByHeights(treeSet: RootedTreeSet, node: Node): Map<number, number>;
abstract computeOffsets(treeSet: RootedTreeSet, node: Node): void; abstract computeOffsets(treeSet: RootedTreeSet, node: Node): void;
@ -33,13 +33,15 @@ abstract class ChildrenSorterStrategy {
parent: Node, parent: Node,
node: Node | null, node: Node | null,
position: PositionType | null, position: PositionType | null,
); ): void;
abstract verify(treeSet: RootedTreeSet, node: Node): void; abstract verify(treeSet: RootedTreeSet, node: Node): void;
abstract getChildDirection(treeSet: RootedTreeSet, node: Node): 1 | -1; abstract getChildDirection(treeSet: RootedTreeSet, node: Node): 1 | -1;
abstract toString(): string; abstract toString(): string;
abstract getVerticalPadding(): number;
} }
export default ChildrenSorterStrategy; export default ChildrenSorterStrategy;

View File

@ -33,6 +33,10 @@ class Node {
// eslint-disable-next-line no-use-before-define // eslint-disable-next-line no-use-before-define
_children!: Node[]; _children!: Node[];
_branchHeight: number;
_heightChanged: boolean;
constructor(id: number, size: SizeType, position: PositionType, sorter: ChildrenSorterStrategy) { constructor(id: number, size: SizeType, position: PositionType, sorter: ChildrenSorterStrategy) {
$assert(typeof id === 'number' && Number.isFinite(id), 'id can not be null'); $assert(typeof id === 'number' && Number.isFinite(id), 'id can not be null');
this._id = id; this._id = id;
@ -42,6 +46,8 @@ class Node {
this.setSize(size); this.setSize(size);
this.setPosition(position); this.setPosition(position);
this.setShrunken(false); this.setShrunken(false);
this._branchHeight = -1;
this._heightChanged = false;
} }
/** */ /** */

View File

@ -19,27 +19,26 @@ import { $assert, $defined } from '@wisemapping/core-js';
import Node from './Node'; import Node from './Node';
import SymmetricSorter from './SymmetricSorter'; import SymmetricSorter from './SymmetricSorter';
import BalancedSorter from './BalancedSorter'; import BalancedSorter from './BalancedSorter';
import RootedTreeSet from './RootedTreeSet';
import SizeType from '../SizeType';
import PositionType from '../PositionType';
import ChildrenSorterStrategy from './ChildrenSorterStrategy';
class OriginalLayout { class OriginalLayout {
constructor(treeSet) { private _treeSet: RootedTreeSet;
constructor(treeSet: RootedTreeSet) {
this._treeSet = treeSet; this._treeSet = treeSet;
} }
/** */ createNode(id: number, size: SizeType, position: PositionType, type: string): Node {
// eslint-disable-next-line class-methods-use-this
createNode(id, size, position, type) {
$assert($defined(id), 'id can not be null'); $assert($defined(id), 'id can not be null');
$assert(size, 'size can not be null'); const strategy: ChildrenSorterStrategy =
$assert(position, 'position can not be null');
$assert(type, 'type can not be null');
const strategy =
type === 'root' ? OriginalLayout.BALANCED_SORTER : OriginalLayout.SYMMETRIC_SORTER; type === 'root' ? OriginalLayout.BALANCED_SORTER : OriginalLayout.SYMMETRIC_SORTER;
return new Node(id, size, position, strategy); return new Node(id, size, position, strategy);
} }
/** */ connectNode(parentId: number, childId: number, order: number): void {
connectNode(parentId, childId, order) {
const parent = this._treeSet.find(parentId); const parent = this._treeSet.find(parentId);
const child = this._treeSet.find(childId); const child = this._treeSet.find(childId);
@ -54,11 +53,12 @@ class OriginalLayout {
sorter.verify(this._treeSet, parent); sorter.verify(this._treeSet, parent);
} }
/** */ disconnectNode(nodeId: number): void {
disconnectNode(nodeId) {
const node = this._treeSet.find(nodeId); const node = this._treeSet.find(nodeId);
const parent = this._treeSet.getParent(node); const parent = this._treeSet.getParent(node);
$assert(parent, 'Node already disconnected'); if (!parent) {
throw new Error('Node already disconnected');
}
// Make it fixed // Make it fixed
node.setFree(false); node.setFree(false);
@ -75,21 +75,18 @@ class OriginalLayout {
parent.getSorter().verify(this._treeSet, parent); parent.getSorter().verify(this._treeSet, parent);
} }
/** */ layout(): void {
layout() {
const roots = this._treeSet.getTreeRoots(); const roots = this._treeSet.getTreeRoots();
roots.forEach((node) => { roots.forEach((node) => {
// Calculate all node heights ... // Calculate all node heights ...
const sorter = node.getSorter(); const sorter = node.getSorter();
const heightById = sorter.computeChildrenIdByHeights(this._treeSet, node); const heightById = sorter.computeChildrenIdByHeights(this._treeSet, node);
this._layoutChildren(node, heightById); this._layoutChildren(node, heightById);
this._fixOverlapping(node, heightById); this._fixOverlapping(node, heightById);
}); });
} }
_layoutChildren(node, heightById) { private _layoutChildren(node: Node, heightById: Map<number, number>): void {
const nodeId = node.getId(); const nodeId = node.getId();
const children = this._treeSet.getChildren(node); const children = this._treeSet.getChildren(node);
const parent = this._treeSet.getParent(node); const parent = this._treeSet.getParent(node);
@ -98,9 +95,9 @@ class OriginalLayout {
// If ether any of the nodes has been changed of position or the height of the children is not // If ether any of the nodes has been changed of position or the height of the children is not
// the same, children nodes must be repositioned .... // the same, children nodes must be repositioned ....
const newBranchHeight = heightById[nodeId]; const newBranchHeight = heightById.get(nodeId)!;
const parentHeightChanged = $defined(parent) ? parent._heightChanged : false; const parentHeightChanged = parent ? parent._heightChanged : false;
const heightChanged = node._branchHeight !== newBranchHeight; const heightChanged = node._branchHeight !== newBranchHeight;
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
node._heightChanged = heightChanged || parentHeightChanged; node._heightChanged = heightChanged || parentHeightChanged;
@ -141,7 +138,6 @@ class OriginalLayout {
me._treeSet.updateBranchPosition(child, newPos); me._treeSet.updateBranchPosition(child, newPos);
}); });
// eslint-disable-next-line no-param-reassign
node._branchHeight = newBranchHeight; node._branchHeight = newBranchHeight;
} }
@ -151,7 +147,7 @@ class OriginalLayout {
}); });
} }
_calculateAlignOffset(node, child, heightById) { private _calculateAlignOffset(node: Node, child: Node, heightById: Map<number, number>): number {
if (child.isFree()) { if (child.isFree()) {
return 0; return 0;
} }
@ -167,8 +163,8 @@ class OriginalLayout {
) { ) {
if (this._treeSet.hasSinglePathToSingleLeaf(child)) { if (this._treeSet.hasSinglePathToSingleLeaf(child)) {
offset = offset =
heightById[child.getId()] / 2 - heightById.get(child.getId())! / 2 -
(childHeight + child.getSorter()._getVerticalPadding() * 2) / 2; (childHeight + child.getSorter().getVerticalPadding() * 2) / 2;
} else { } else {
offset = this._treeSet.isLeaf(child) ? 0 : -(childHeight - nodeHeight) / 2; offset = this._treeSet.isLeaf(child) ? 0 : -(childHeight - nodeHeight) / 2;
} }
@ -189,13 +185,14 @@ class OriginalLayout {
return offset; return offset;
} }
static _branchIsTaller(node, heightById) { static _branchIsTaller(node: Node, heightById: Map<number, number>): boolean {
return ( return (
heightById[node.getId()] > node.getSize().height + node.getSorter()._getVerticalPadding() * 2 heightById.get(node.getId())! >
node.getSize().height + node.getSorter().getVerticalPadding() * 2
); );
} }
_fixOverlapping(node, heightById) { private _fixOverlapping(node: Node, heightById: Map<number, number>): void {
const children = this._treeSet.getChildren(node); const children = this._treeSet.getChildren(node);
if (node.isFree()) { if (node.isFree()) {
@ -206,7 +203,7 @@ class OriginalLayout {
}); });
} }
_shiftBranches(node, heightById) { _shiftBranches(node: Node, heightById: Map<number, number>): void {
const shiftedBranches = [node]; const shiftedBranches = [node];
const siblingsToShift = this._treeSet.getSiblingsInVerticalDirection( const siblingsToShift = this._treeSet.getSiblingsInVerticalDirection(
@ -238,28 +235,22 @@ class OriginalLayout {
}); });
} }
static _branchesOverlap(branchA, branchB, heightById) { static _branchesOverlap(branchA: Node, branchB: Node, heightById: Map<number, number>): boolean {
// a branch doesn't really overlap with itself // a branch doesn't really overlap with itself
if (branchA === branchB) { if (branchA === branchB) {
return false; return false;
} }
const topA = branchA.getPosition().y - heightById[branchA.getId()] / 2; const topA = branchA.getPosition().y - heightById.get(branchA.getId())! / 2;
const bottomA = branchA.getPosition().y + heightById[branchA.getId()] / 2; const bottomA = branchA.getPosition().y + heightById.get(branchA.getId())! / 2;
const topB = branchB.getPosition().y - heightById[branchB.getId()] / 2; const topB = branchB.getPosition().y - heightById.get(branchB.getId())! / 2;
const bottomB = branchB.getPosition().y + heightById[branchB.getId()] / 2; const bottomB = branchB.getPosition().y + heightById.get(branchB.getId())! / 2;
return !(topA >= bottomB || bottomA <= topB); return !(topA >= bottomB || bottomA <= topB);
} }
static SYMMETRIC_SORTER: ChildrenSorterStrategy = new SymmetricSorter();
static BALANCED_SORTER: ChildrenSorterStrategy = new BalancedSorter();
} }
/**
* @type {mindplot.layout.SymmetricSorter}
*/
OriginalLayout.SYMMETRIC_SORTER = new SymmetricSorter();
/**
* @type {mindplot.layout.BalancedSorter}
*/
OriginalLayout.BALANCED_SORTER = new BalancedSorter();
export default OriginalLayout; export default OriginalLayout;

View File

@ -25,7 +25,13 @@ class SymmetricSorter extends AbstractBasicSorter {
/** /**
* Predict the order and position of a dragged node. * Predict the order and position of a dragged node.
*/ */
predict(graph: RootedTreeSet, parent: Node, node: Node, position: PositionType, free?: boolean) { predict(
graph: RootedTreeSet,
parent: Node,
node: Node,
position: PositionType,
free?: boolean,
): [number, PositionType] {
const self = this; const self = this;
const rootNode = graph.getRootNode(parent); const rootNode = graph.getRootNode(parent);
@ -97,7 +103,7 @@ class SymmetricSorter extends AbstractBasicSorter {
const last = parentChildren[parentChildren.length - 1]; const last = parentChildren[parentChildren.length - 1];
for (let i = 0; i < parentChildren.length; i++) { for (let i = 0; i < parentChildren.length; i++) {
const parentChild = parentChildren[i]; const parentChild = parentChildren[i];
const nodeAfter = i + 1 === parentChildren.length ? null : parentChildren[i + 1]; const nodeAfter = parentChildren[i + 1];
// Fit at the bottom // Fit at the bottom
if (!nodeAfter && position.y > parentChild.getPosition().y) { if (!nodeAfter && position.y > parentChild.getPosition().y) {
@ -291,7 +297,7 @@ class SymmetricSorter extends AbstractBasicSorter {
return 'Symmetric Sorter'; return 'Symmetric Sorter';
} }
protected _getVerticalPadding() { getVerticalPadding() {
return SymmetricSorter.INTERNODE_VERTICAL_PADDING; return SymmetricSorter.INTERNODE_VERTICAL_PADDING;
} }