wisemapping-frontend/packages/mindplot/src/components/DragConnector.ts

141 lines
4.9 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.
*/
2021-12-04 01:11:17 +01:00
import { $assert } from '@wisemapping/core-js';
2022-02-24 00:44:37 +01:00
import DesignerModel from './DesignerModel';
import DragTopic from './DragTopic';
import SizeType from './SizeType';
import Topic from './Topic';
2023-02-10 03:51:52 +01:00
import Canvas from './Canvas';
import PositionType from './PositionType';
2021-12-05 00:39:20 +01:00
class DragConnector {
2022-02-24 00:44:37 +01:00
private _designerModel: DesignerModel;
2023-02-10 03:51:52 +01:00
private _workspace: Canvas;
2022-02-24 00:44:37 +01:00
2023-02-10 03:51:52 +01:00
constructor(designerModel: DesignerModel, workspace: Canvas) {
2021-10-05 02:05:34 +02:00
$assert(designerModel, 'designerModel can not be null');
$assert(workspace, 'workspace can not be null');
2021-07-16 16:41:58 +02:00
2021-10-05 02:05:34 +02:00
this._designerModel = designerModel;
this._workspace = workspace;
2021-12-05 00:39:20 +01:00
}
2021-10-05 02:05:34 +02:00
2023-01-07 08:57:39 +01:00
checkConnection(dragTopic: DragTopic, forceDisconnected: boolean): void {
// Is forced disconexion enabled ?
let candidates: Topic[] = [];
if (!forceDisconnected) {
candidates = this._searchConnectionCandidates(dragTopic);
}
2021-10-05 02:05:34 +02:00
// Must be disconnected from their current connection ?.
const currentConnection = dragTopic.getConnectedToTopic();
if (currentConnection && (candidates.length === 0 || candidates[0] !== currentConnection)) {
2021-10-05 02:05:34 +02:00
dragTopic.disconnect(this._workspace);
}
// Finally, connect nodes ...
if (!dragTopic.isConnected() && candidates.length > 0) {
dragTopic.connectTo(candidates[0]);
2021-07-16 16:41:58 +02:00
}
2021-12-05 00:39:20 +01:00
}
2021-10-05 02:05:34 +02:00
2022-02-24 00:44:37 +01:00
private _searchConnectionCandidates(dragTopic: DragTopic): Topic[] {
2021-10-05 02:05:34 +02:00
let topics = this._designerModel.getTopics();
const draggedNode = dragTopic.getDraggedTopic();
// Drag node connects to the border ...
2022-02-24 00:44:37 +01:00
// const dragTopicWidth = dragTopic.getSize ? dragTopic.getSize().width : 0; // Hack...
const dragTopicWidth = 0;
2021-10-05 02:05:34 +02:00
const xMouseGap = dragTopic.getPosition().x > 0 ? 0 : dragTopicWidth;
const sPos = { x: dragTopic.getPosition().x - xMouseGap, y: dragTopic.getPosition().y };
// Perform a initial filter to discard topics:
// - Exclude dragged topic
// - Exclude dragTopic pivot
// - Nodes that are collapsed
// - It's not part of the branch dragged itself
2022-02-24 00:44:37 +01:00
topics = topics.filter((topic: Topic) => {
2021-12-14 18:06:09 +01:00
let result = draggedNode !== topic;
result = result && topic !== draggedNode;
2021-10-05 02:05:34 +02:00
result = result && !topic.areChildrenShrunken() && !topic.isCollapsed();
result = result && !draggedNode.isChildTopic(topic);
return result;
});
// Filter all the nodes that are outside the vertical boundary:
// * The node is to out of the x scope
// * The x distance greater the vertical tolerated distance
2022-02-24 00:44:37 +01:00
topics = topics.filter((topic: Topic) => {
2021-10-05 02:05:34 +02:00
const tpos = topic.getPosition();
// Center topic has different alignment than the rest of the nodes.
// That's why i need to divide it by two...
2021-10-05 02:05:34 +02:00
const txborder = tpos.x + (topic.getSize().width / 2) * Math.sign(sPos.x);
const distance = (sPos.x - txborder) * Math.sign(sPos.x);
2022-07-13 03:45:36 +02:00
return distance > 0 && distance < DragConnector.MAX_VERTICAL_CONNECTION_TOLERANCE;
2021-10-05 02:05:34 +02:00
});
// Assign a priority based on the distance:
// - Alignment with the targetNode
// - Vertical distance
// - Horizontal proximity
// - It's already connected.
const currentConnection = dragTopic.getConnectedToTopic();
const me = this;
topics = topics.sort((a, b) => {
const aPos = a.getPosition();
const bPos = b.getPosition();
const av = me._isVerticallyAligned(a.getSize(), aPos, sPos);
const bv = me._isVerticallyAligned(b.getSize(), bPos, sPos);
2022-07-13 03:45:36 +02:00
return (
2022-12-10 07:39:53 +01:00
me._proximityWeight(av, a, sPos, currentConnection!) -
me._proximityWeight(bv, b, sPos, currentConnection!)
2022-07-13 03:45:36 +02:00
);
2021-10-05 02:05:34 +02:00
});
return topics;
2021-12-05 00:39:20 +01:00
}
2021-10-05 02:05:34 +02:00
2022-07-13 03:45:36 +02:00
private _proximityWeight(
isAligned: boolean,
target: Topic,
2023-02-10 03:51:52 +01:00
sPos: PositionType,
2022-07-13 03:45:36 +02:00
currentConnection: Topic,
): number {
2021-10-05 02:05:34 +02:00
const tPos = target.getPosition();
2022-07-13 03:45:36 +02:00
return (
(isAligned ? 0 : 200) +
Math.abs(tPos.x - sPos.x) +
Math.abs(tPos.y - sPos.y) +
(currentConnection === target ? 0 : 100)
);
2021-12-05 00:39:20 +01:00
}
2021-10-05 02:05:34 +02:00
2022-07-13 03:45:36 +02:00
private _isVerticallyAligned(
targetSize: SizeType,
2023-02-10 03:51:52 +01:00
targetPosition: PositionType,
sourcePosition: PositionType,
2022-07-13 03:45:36 +02:00
): boolean {
2021-10-05 02:05:34 +02:00
return Math.abs(sourcePosition.y - targetPosition.y) < targetSize.height / 2;
2021-12-05 00:39:20 +01:00
}
2021-07-16 16:41:58 +02:00
2022-02-24 00:44:37 +01:00
static MAX_VERTICAL_CONNECTION_TOLERANCE = 80;
}
2021-07-16 16:41:58 +02:00
2021-10-05 02:05:34 +02:00
export default DragConnector;