230 lines
6.3 KiB
TypeScript
230 lines
6.3 KiB
TypeScript
/*
|
|
* Copyright [2021] [wisemapping]
|
|
*
|
|
* 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 { $assert } from '@wisemapping/core-js';
|
|
import { CurvedLine, Line, PolyLine } from '@wisemapping/web2d';
|
|
import PositionType from './PositionType';
|
|
import Topic from './Topic';
|
|
import TopicConfig from './TopicConfig';
|
|
import Canvas from './Canvas';
|
|
|
|
// eslint-disable-next-line no-shadow
|
|
export enum LineType {
|
|
THIN_CURVED,
|
|
POLYLINE_MIDDLE,
|
|
POLYLINE_CURVED,
|
|
THICK_CURVED,
|
|
}
|
|
|
|
class ConnectionLine {
|
|
protected _targetTopic: Topic;
|
|
|
|
protected _sourceTopic: Topic;
|
|
|
|
protected _line: Line;
|
|
|
|
private _type: LineType;
|
|
|
|
private _color: string;
|
|
|
|
constructor(sourceNode: Topic, targetNode: Topic, type: LineType = LineType.THIN_CURVED) {
|
|
$assert(sourceNode !== targetNode, 'Circular connection');
|
|
|
|
this._targetTopic = targetNode;
|
|
this._sourceTopic = sourceNode;
|
|
this._type = type;
|
|
this._line = this.createLine(type);
|
|
this._color = this.updateColor();
|
|
}
|
|
|
|
private _getCtrlPoints(sourceNode: Topic, targetNode: Topic): [PositionType, PositionType] {
|
|
const srcPos = sourceNode.workoutOutgoingConnectionPoint(targetNode.getPosition());
|
|
const destPos = targetNode.workoutIncomingConnectionPoint(sourceNode.getPosition());
|
|
const deltaX = (srcPos.x - destPos.x) / 3;
|
|
return [
|
|
{ x: deltaX, y: 0 },
|
|
{ x: -deltaX, y: 0 },
|
|
];
|
|
}
|
|
|
|
protected createLine(lineType: LineType): Line {
|
|
let line: Line;
|
|
switch (lineType) {
|
|
case LineType.POLYLINE_MIDDLE:
|
|
line = new PolyLine();
|
|
(line as PolyLine).setStyle('MiddleStraight');
|
|
break;
|
|
case LineType.POLYLINE_CURVED:
|
|
line = new PolyLine();
|
|
(line as PolyLine).setStyle('Curved');
|
|
break;
|
|
case LineType.THIN_CURVED:
|
|
line = new CurvedLine();
|
|
break;
|
|
case LineType.THICK_CURVED:
|
|
line = new CurvedLine();
|
|
(line as CurvedLine).setWidth(this._targetTopic.isCentralTopic() ? 15 : 3);
|
|
break;
|
|
default:
|
|
throw new Error(`Unexpected line type. ${lineType}`);
|
|
}
|
|
return line;
|
|
}
|
|
|
|
private updateColor(): string {
|
|
// In case that the main topic has changed the color, overwrite the main topic definiton.
|
|
let color = this._targetTopic.getConnectionColor();
|
|
if (this._targetTopic.isCentralTopic()) {
|
|
color = this._sourceTopic.getModel().getConnectionColor() || color;
|
|
}
|
|
|
|
this._color = color;
|
|
switch (this._type) {
|
|
case LineType.POLYLINE_MIDDLE:
|
|
this._line.setStroke(1, 'solid', color, 1);
|
|
break;
|
|
case LineType.POLYLINE_CURVED:
|
|
this._line.setStroke(1, 'solid', color, 1);
|
|
break;
|
|
case LineType.THIN_CURVED:
|
|
this._line.setStroke(1, 'solid', color, 1);
|
|
this._line.setFill(color, 1);
|
|
break;
|
|
case LineType.THICK_CURVED:
|
|
this._line.setStroke(1, 'solid', color, 1);
|
|
this._line.setFill(color, 1);
|
|
break;
|
|
default:
|
|
throw new Error(`Unexpected line type. ${this._type}`);
|
|
}
|
|
return color;
|
|
}
|
|
|
|
setVisibility(value: boolean, fade = 0): void {
|
|
this._line.setVisibility(value, fade);
|
|
}
|
|
|
|
isVisible(): boolean {
|
|
return this._line.isVisible();
|
|
}
|
|
|
|
setOpacity(opacity: number): void {
|
|
this._line.setOpacity(opacity);
|
|
}
|
|
|
|
redraw(): void {
|
|
const line2d = this._line;
|
|
const sourceTopic = this._sourceTopic;
|
|
const sourcePosition = sourceTopic.getPosition();
|
|
|
|
const targetTopic = this._targetTopic;
|
|
const targetPosition = targetTopic.getPosition();
|
|
|
|
const sPos = sourceTopic.workoutOutgoingConnectionPoint(targetPosition);
|
|
const tPos = targetTopic.workoutIncomingConnectionPoint(sourcePosition);
|
|
|
|
line2d.setFrom(tPos.x, tPos.y);
|
|
line2d.setTo(sPos.x, sPos.y);
|
|
|
|
if (this._type === LineType.THICK_CURVED || this._type === LineType.THIN_CURVED) {
|
|
const ctrlPoints = this._getCtrlPoints(this._sourceTopic, this._targetTopic);
|
|
(line2d as CurvedLine).setSrcControlPoint(ctrlPoints[0]);
|
|
(line2d as CurvedLine).setDestControlPoint(ctrlPoints[1]);
|
|
}
|
|
|
|
// Add connector ...
|
|
this._positionLine(targetTopic);
|
|
|
|
// Update color ...
|
|
this.updateColor();
|
|
}
|
|
|
|
protected _positionLine(targetTopic: Topic): void {
|
|
const targetPosition = targetTopic.getPosition();
|
|
const offset = TopicConfig.CONNECTOR_WIDTH / 2;
|
|
const targetTopicSize = targetTopic.getSize();
|
|
let y: number;
|
|
let x: number;
|
|
if (targetTopic.getShapeType() === 'line') {
|
|
y = targetTopicSize.height;
|
|
} else {
|
|
y = targetTopicSize.height / 2;
|
|
}
|
|
y -= offset;
|
|
|
|
const connector = targetTopic.getShrinkConnector();
|
|
if (connector) {
|
|
if (Math.sign(targetPosition.x) > 0) {
|
|
x = targetTopicSize.width;
|
|
connector.setPosition(x, y);
|
|
} else {
|
|
x = -TopicConfig.CONNECTOR_WIDTH;
|
|
}
|
|
connector.setPosition(x, y);
|
|
}
|
|
}
|
|
|
|
setStroke(color: string, style: string, opacity: number) {
|
|
this._line.setStroke(1, style, color, opacity);
|
|
this._color = color;
|
|
}
|
|
|
|
getStrokeColor(): string {
|
|
return this._color;
|
|
}
|
|
|
|
addToWorkspace(workspace: Canvas) {
|
|
workspace.append(this._line.getElementClass());
|
|
this._line.moveToBack();
|
|
}
|
|
|
|
removeFromWorkspace(workspace: Canvas) {
|
|
workspace.removeChild(this._line.getElementClass());
|
|
}
|
|
|
|
getTargetTopic(): Topic {
|
|
return this._targetTopic;
|
|
}
|
|
|
|
getSourceTopic(): Topic {
|
|
return this._sourceTopic;
|
|
}
|
|
|
|
getLineType(): number {
|
|
return this._type;
|
|
}
|
|
|
|
getLine(): Line {
|
|
return this._line;
|
|
}
|
|
|
|
getType(): string {
|
|
return 'ConnectionLine';
|
|
}
|
|
|
|
moveToBack(): void {
|
|
this._line.moveToBack();
|
|
}
|
|
|
|
moveToFront() {
|
|
this._line.moveToFront();
|
|
}
|
|
}
|
|
|
|
export default ConnectionLine;
|