wisemapping-frontend/packages/mindplot/src/components/layout/LayoutManager.ts

214 lines
6.2 KiB
TypeScript
Raw Normal View History

2021-07-16 16:41:58 +02:00
/*
2021-12-25 23:39:34 +01:00
* Copyright [2021] [wisemapping]
2021-07-16 16:41:58 +02:00
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import $ from 'jquery';
2021-12-04 01:11:17 +01:00
import { $assert, $defined } from '@wisemapping/core-js';
import Events from '../Events';
import RootedTreeSet from './RootedTreeSet';
import OriginalLayout from './OriginalLayout';
import ChangeEvent from './ChangeEvent';
2022-03-01 01:12:45 +01:00
import SizeType from '../SizeType';
import Node from './Node';
import PositionType from '../PositionType';
2021-07-16 16:41:58 +02:00
2021-12-04 01:11:17 +01:00
class LayoutManager extends Events {
2022-03-01 01:12:45 +01:00
private _treeSet: RootedTreeSet;
private _layout: OriginalLayout;
private _events: ChangeEvent[];
constructor(rootNodeId: number, rootSize: SizeType) {
2021-12-04 01:11:17 +01:00
super();
$assert($defined(rootNodeId), 'rootNodeId can not be null');
$assert(rootSize, 'rootSize can not be null');
this._treeSet = new RootedTreeSet();
this._layout = new OriginalLayout(this._treeSet);
2021-12-19 18:56:22 +01:00
const rootNode = this._layout.createNode(rootNodeId, rootSize, { x: 0, y: 0 }, 'root');
2021-12-04 01:11:17 +01:00
this._treeSet.setRoot(rootNode);
this._events = [];
}
2022-03-01 01:12:45 +01:00
updateNodeSize(id: number, size: SizeType): void {
2021-12-04 01:11:17 +01:00
$assert($defined(id), 'id can not be null');
const node = this._treeSet.find(id);
node.setSize(size);
}
2022-03-01 01:12:45 +01:00
updateShrinkState(id: number, value: boolean): void {
2021-12-04 01:11:17 +01:00
$assert($defined(id), 'id can not be null');
$assert($defined(value), 'value can not be null');
const node = this._treeSet.find(id);
node.setShrunken(value);
}
2022-03-01 01:12:45 +01:00
find(id: number): Node {
2021-12-04 01:11:17 +01:00
return this._treeSet.find(id);
}
/**
* @param id
* @param position
* @throws will throw an error if id is null or undefined
* @throws will throw an error if position is null or undefined
* @throws will throw an error if the position's x property is null or undefined
* @throws will throw an error if the position's y property is null or undefined
*/
2022-03-01 01:12:45 +01:00
moveNode(id: number, position: PositionType) {
2021-12-04 01:11:17 +01:00
$assert($defined(id), 'id cannot be null');
$assert($defined(position), 'position cannot be null');
$assert($defined(position.x), 'x can not be null');
$assert($defined(position.y), 'y can not be null');
const node = this._treeSet.find(id);
node.setPosition(position);
}
2022-03-01 01:12:45 +01:00
connectNode(parentId: number, childId: number, order: number) {
2021-12-04 01:11:17 +01:00
$assert($defined(parentId), 'parentId cannot be null');
$assert($defined(childId), 'childId cannot be null');
$assert($defined(order), 'order cannot be null');
this._layout.connectNode(parentId, childId, order);
return this;
}
2022-03-01 01:12:45 +01:00
disconnectNode(id: number): void {
2021-12-04 01:11:17 +01:00
$assert($defined(id), 'id can not be null');
this._layout.disconnectNode(id);
}
/**
* @param id
* @param size
* @param position
* @throws will throw an error if id is null or undefined
* @return this
*/
2022-03-01 01:12:45 +01:00
addNode(id: number, size: SizeType, position: PositionType) {
2021-12-04 01:11:17 +01:00
$assert($defined(id), 'id can not be null');
const result = this._layout.createNode(id, size, position, 'topic');
this._treeSet.add(result);
return this;
}
2022-03-01 01:12:45 +01:00
removeNode(id: number) {
2021-12-04 01:11:17 +01:00
$assert($defined(id), 'id can not be null');
const node = this._treeSet.find(id);
// Is It connected ?
if (this._treeSet.getParent(node)) {
this.disconnectNode(id);
}
// Remove the all the branch ...
this._treeSet.remove(id);
return this;
}
2022-03-01 01:12:45 +01:00
predict(parentId: number, nodeId: number, position: PositionType): { order: number, position: PositionType } {
2021-12-04 01:11:17 +01:00
$assert($defined(parentId), 'parentId can not be null');
const parent = this._treeSet.find(parentId);
const node = nodeId ? this._treeSet.find(nodeId) : null;
const sorter = parent.getSorter();
2022-03-01 01:12:45 +01:00
const result = sorter.predict(this._treeSet, parent, node, position);
2021-12-04 01:11:17 +01:00
return { order: result[0], position: result[1] };
}
dump() {
console.log(this._treeSet.dump());
}
2022-03-01 01:12:45 +01:00
plot(containerId: string, size = { width: 200, height: 200 }) {
2021-12-04 01:11:17 +01:00
// this method is only used from tests that include Raphael
2022-03-01 01:12:45 +01:00
if (!globalThis.Raphael) {
2021-12-04 01:11:17 +01:00
console.warn('Raphael.js not found, exiting plot()');
return null;
}
$assert(containerId, 'containerId cannot be null');
const squaresize = 10;
2022-03-01 01:12:45 +01:00
const canvas = globalThis.Raphael(containerId, size.width, size.height);
2021-12-04 01:11:17 +01:00
canvas.drawGrid(
0,
0,
size.width,
size.height,
size.width / squaresize,
size.height / squaresize,
);
this._treeSet.plot(canvas);
return canvas;
}
2022-03-01 01:12:45 +01:00
layout(flush: boolean): LayoutManager {
2021-12-04 01:11:17 +01:00
// File repositioning ...
this._layout.layout();
// Collect changes ...
2022-03-01 01:12:45 +01:00
this._collectChanges(this._treeSet.getTreeRoots());
2021-12-04 01:11:17 +01:00
2022-03-01 01:12:45 +01:00
if (flush) {
2021-12-04 01:11:17 +01:00
this._flushEvents();
}
return this;
}
2022-03-01 01:12:45 +01:00
private _flushEvents() {
2021-12-05 17:14:15 +01:00
this._events.forEach(((event) => {
this.fireEvent('change', event);
}));
2021-12-04 01:11:17 +01:00
this._events = [];
}
2022-03-01 01:12:45 +01:00
private _collectChanges(nodes: Node[]) {
nodes.forEach(((node) => {
2021-12-05 17:14:15 +01:00
if (node.hasOrderChanged() || node.hasPositionChanged()) {
// Find or create a event ...
const id = node.getId();
2022-03-01 01:12:45 +01:00
let event: ChangeEvent = this._events.find((e) => e.getId() === id);
2021-12-05 17:14:15 +01:00
if (!event) {
event = new ChangeEvent(id);
2021-12-04 01:11:17 +01:00
}
2021-12-05 17:14:15 +01:00
// Update nodes ...
event.setOrder(node.getOrder());
event.setPosition(node.getPosition());
node.resetPositionState();
node.resetOrderState();
node.resetFreeState();
this._events.push(event);
}
this._collectChanges(this._treeSet.getChildren(node));
}));
2021-12-04 01:11:17 +01:00
}
}
2021-07-16 16:41:58 +02:00
export default LayoutManager;