406 lines
11 KiB
TypeScript
Raw Normal View History

2021-07-16 11:41:58 -03:00
/*
2021-12-25 14:39:34 -08:00
* Copyright [2021] [wisemapping]
2021-07-16 11:41:58 -03: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-03 16:11:17 -08:00
import { $assert, $defined } from '@wisemapping/core-js';
2022-11-27 10:22:19 -08:00
import { Arrow, Point, CurvedLine } from '@wisemapping/web2d';
2022-12-09 20:56:01 -08:00
import ConnectionLine, { LineType } from './ConnectionLine';
2022-11-26 08:47:35 -08:00
import RelationshipControlPoints from './RelationshipControlPoints';
2022-01-24 11:24:16 -08:00
import RelationshipModel from './model/RelationshipModel';
2022-03-07 19:43:04 -08:00
import PositionType from './PositionType';
2022-02-14 19:01:48 -08:00
import Topic from './Topic';
import Shape from './util/Shape';
2022-03-07 19:43:04 -08:00
import Workspace from './Workspace';
2021-07-16 11:41:58 -03:00
2021-12-04 15:39:20 -08:00
class Relationship extends ConnectionLine {
2022-11-27 10:22:19 -08:00
private _focusShape: CurvedLine;
2022-01-24 11:24:16 -08:00
private _onFocus: boolean;
private _isInWorkspace: boolean;
2022-11-26 08:47:35 -08:00
private _controlPointsController: RelationshipControlPoints;
2022-01-24 11:24:16 -08:00
private _startArrow: Arrow;
private _showEndArrow: Arrow;
private _endArrow: Arrow;
2022-11-27 21:28:32 -08:00
private _onFocusHandler: (event: MouseEvent) => void;
2022-01-24 11:24:16 -08:00
private _showStartArrow: Arrow;
2022-12-22 00:13:23 -08:00
private _model: RelationshipModel;
2022-02-14 19:01:48 -08:00
constructor(sourceNode: Topic, targetNode: Topic, model: RelationshipModel) {
2021-10-04 17:05:34 -07:00
$assert(sourceNode, 'sourceNode can not be null');
$assert(targetNode, 'targetNode can not be null');
2022-12-09 20:56:01 -08:00
super(sourceNode, targetNode);
2022-12-22 00:13:23 -08:00
this._model = model;
2021-10-04 17:05:34 -07:00
const strokeColor = Relationship.getStrokeColor();
2022-11-27 10:22:19 -08:00
// Build line ..
2021-10-04 17:05:34 -07:00
this._line2d.setIsSrcControlPointCustom(false);
this._line2d.setIsDestControlPointCustom(false);
this._line2d.setCursor('pointer');
this._line2d.setStroke(1, 'solid', strokeColor);
this._line2d.setDashed(4, 2);
2022-01-26 19:25:11 +00:00
this._line2d.setTestId(`${model.getFromNode()}-${model.getToNode()}-relationship`);
2022-11-27 10:22:19 -08:00
// Build focus shape ...
2022-12-09 20:56:01 -08:00
this._focusShape = this._createLine(LineType.SIMPLE_CURVED);
2022-11-27 21:28:32 -08:00
this._focusShape.setStroke(8, 'solid', '#3f96ff');
2022-11-27 10:22:19 -08:00
this._focusShape.setIsSrcControlPointCustom(false);
this._focusShape.setIsDestControlPointCustom(false);
2022-11-27 21:28:32 -08:00
this._focusShape.setVisibility(true);
this._focusShape.setOpacity(0);
this._focusShape.setCursor('pointer');
2021-10-04 17:05:34 -07:00
2022-11-27 10:22:19 -08:00
// Build arrow ...
2021-12-19 08:31:29 -08:00
this._startArrow = new Arrow();
2021-10-04 17:05:34 -07:00
this._startArrow.setStrokeColor(strokeColor);
this._startArrow.setStrokeWidth(2);
this.setShowStartArrow(true);
// Share style is disable ...
if (this._showEndArrow) {
2021-12-19 08:31:29 -08:00
this._endArrow = new Arrow();
2021-10-04 17:05:34 -07:00
this._endArrow.setStrokeColor(strokeColor);
this._endArrow.setStrokeWidth(2);
}
2022-11-27 10:22:19 -08:00
this._onFocus = false;
this._isInWorkspace = false;
this._controlPointsController = new RelationshipControlPoints(this);
2021-07-16 11:41:58 -03:00
2021-10-04 17:05:34 -07:00
// Position the line ...
2022-11-26 08:47:35 -08:00
if (model.getSrcCtrlPoint()) {
2021-12-14 17:06:09 +00:00
const srcPoint = { ...model.getSrcCtrlPoint() };
2021-10-04 17:05:34 -07:00
this.setSrcControlPoint(srcPoint);
}
2022-11-26 08:47:35 -08:00
if (model.getDestCtrlPoint()) {
2021-12-14 17:06:09 +00:00
const destPoint = { ...model.getDestCtrlPoint() };
2021-10-04 17:05:34 -07:00
this.setDestControlPoint(destPoint);
}
2022-11-27 10:22:19 -08:00
// Reposition all nodes ...
2022-11-27 21:28:32 -08:00
this.updatePositions();
2022-11-27 10:22:19 -08:00
this._controlPointsController = new RelationshipControlPoints(this);
2022-11-27 21:28:32 -08:00
// Initialize handler ..
this._onFocusHandler = (event) => {
this.setOnFocus(true);
event.stopPropagation();
event.preventDefault();
};
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-01-24 11:24:16 -08:00
setStroke(color: string, style: string, opacity: number): void {
2021-12-05 09:25:16 -08:00
super.setStroke(color, style, opacity);
2021-10-04 17:05:34 -07:00
this._startArrow.setStrokeColor(color);
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-12-22 00:13:23 -08:00
getModel(): RelationshipModel {
return this._model;
}
2022-11-27 21:28:32 -08:00
private updatePositions() {
2021-10-04 17:05:34 -07:00
const line2d = this._line2d;
const sourceTopic = this._sourceTopic;
2022-11-27 10:22:19 -08:00
const sPos = sourceTopic.getPosition();
2021-10-04 17:05:34 -07:00
const targetTopic = this._targetTopic;
2022-11-27 10:22:19 -08:00
let tPos = targetTopic.getPosition();
2022-01-02 14:16:18 -08:00
if (targetTopic.getType() === 'CentralTopic') {
2022-11-27 10:22:19 -08:00
tPos = Shape.workoutIncomingConnectionPoint(targetTopic, sPos);
2021-10-04 17:05:34 -07:00
}
2021-07-16 11:41:58 -03:00
2021-10-04 17:05:34 -07:00
this._line2d.setStroke(2);
2022-11-27 10:22:19 -08:00
let ctrlPoints: [Point, Point];
2021-10-04 17:05:34 -07:00
2022-11-27 10:22:19 -08:00
// Position line ...
if (!line2d.isDestControlPointCustom() && !line2d.isSrcControlPointCustom()) {
ctrlPoints = Shape.calculateDefaultControlPoints(sPos, tPos) as [PositionType, PositionType];
} else {
ctrlPoints = line2d.getControlPoints();
2021-10-04 17:05:34 -07:00
}
2021-12-14 15:08:54 +00:00
2022-11-27 10:22:19 -08:00
const spointX = ctrlPoints[0].x + sPos.x;
const spointY = ctrlPoints[0].y + sPos.y;
2021-07-16 11:41:58 -03:00
2022-11-27 10:22:19 -08:00
const tpointX = ctrlPoints[1].x + tPos.x;
const tpointY = ctrlPoints[1].y + tPos.y;
2021-07-16 11:41:58 -03:00
2022-11-27 10:22:19 -08:00
const nsPos = Shape.calculateRelationShipPointCoordinates(
sourceTopic,
new Point(spointX, spointY),
);
const ntPos = Shape.calculateRelationShipPointCoordinates(
targetTopic,
new Point(tpointX, tpointY),
);
2021-07-16 11:41:58 -03:00
2022-11-27 10:22:19 -08:00
line2d.setFrom(nsPos.x, nsPos.y);
line2d.setTo(ntPos.x, ntPos.y);
2021-07-16 11:41:58 -03:00
2021-10-04 17:05:34 -07:00
// Positionate Arrows
2022-11-27 21:28:32 -08:00
this.positionArrows();
2021-07-16 11:41:58 -03:00
2021-10-04 17:05:34 -07:00
// Add connector ...
this._positionateConnector(targetTopic);
2021-07-16 11:41:58 -03:00
2022-11-27 10:22:19 -08:00
// Poisition refresh shape ...
2022-11-27 21:28:32 -08:00
this.positionRefreshShape();
2022-11-27 10:22:19 -08:00
}
redraw(): void {
2022-11-27 21:28:32 -08:00
this.updatePositions();
2022-11-27 10:22:19 -08:00
this._line2d.moveToFront();
this._startArrow.moveToBack();
if (this._endArrow) {
this._endArrow.moveToBack();
2021-10-04 17:05:34 -07:00
}
2022-11-26 08:47:35 -08:00
2022-11-27 10:22:19 -08:00
if (this._showEndArrow) {
this._endArrow.setVisibility(this.isVisible());
}
this._startArrow.setVisibility(this.isVisible() && this._showStartArrow);
this._focusShape.moveToBack();
2021-10-04 17:05:34 -07:00
this._controlPointsController.redraw();
2021-12-04 15:39:20 -08:00
}
2021-07-16 11:41:58 -03:00
2022-11-27 21:28:32 -08:00
private positionArrows(): void {
2021-10-04 17:05:34 -07:00
const tpos = this._line2d.getTo();
const spos = this._line2d.getFrom();
2021-07-16 11:41:58 -03:00
2021-10-04 17:05:34 -07:00
this._startArrow.setFrom(spos.x, spos.y);
if (this._endArrow) {
this._endArrow.setFrom(tpos.x, tpos.y);
}
2021-07-16 11:41:58 -03:00
if (this._line2d.getType() === 'CurvedLine') {
2021-10-04 17:05:34 -07:00
const controlPoints = this._line2d.getControlPoints();
this._startArrow.setControlPoint(controlPoints[0]);
if (this._endArrow) {
this._endArrow.setControlPoint(controlPoints[1]);
}
} else {
this._startArrow.setControlPoint(this._line2d.getTo());
if (this._endArrow) {
this._endArrow.setControlPoint(this._line2d.getFrom());
}
}
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-03-07 19:43:04 -08:00
addToWorkspace(workspace: Workspace): void {
2022-11-27 21:28:32 -08:00
this.updatePositions();
2022-11-27 10:22:19 -08:00
2021-10-04 17:05:34 -07:00
workspace.append(this._focusShape);
workspace.append(this._controlPointsController);
2022-01-24 10:46:57 -08:00
if (workspace.isReadOnly()) {
this._line2d.setCursor('default');
} else {
2022-11-27 21:28:32 -08:00
this._line2d.addEvent('click', this._onFocusHandler);
this._focusShape.addEvent('click', this._onFocusHandler);
}
2021-10-04 17:05:34 -07:00
this._isInWorkspace = true;
workspace.append(this._startArrow);
if (this._endArrow) workspace.append(this._endArrow);
2021-12-05 09:25:16 -08:00
super.addToWorkspace(workspace);
2022-11-27 21:28:32 -08:00
this.positionArrows();
2021-10-04 17:05:34 -07:00
this.redraw();
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-03-07 19:43:04 -08:00
removeFromWorkspace(workspace: Workspace): void {
2021-10-04 17:05:34 -07:00
workspace.removeChild(this._focusShape);
workspace.removeChild(this._controlPointsController);
2022-11-26 08:47:35 -08:00
2022-11-27 21:28:32 -08:00
this._line2d.removeEvent('click', this._onFocusHandler);
2021-10-04 17:05:34 -07:00
this._isInWorkspace = false;
workspace.removeChild(this._startArrow);
2022-11-26 08:47:35 -08:00
if (this._endArrow) {
workspace.removeChild(this._endArrow);
}
2021-10-04 17:05:34 -07:00
2021-12-05 09:25:16 -08:00
super.removeFromWorkspace(workspace);
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
getType() {
2022-01-24 11:24:16 -08:00
return 'Relationship';
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-01-24 11:24:16 -08:00
setOnFocus(focus: boolean): void {
2022-11-27 10:22:19 -08:00
if (focus) {
2022-11-27 21:28:32 -08:00
this.positionRefreshShape();
2022-11-27 10:22:19 -08:00
}
2021-10-04 17:05:34 -07:00
// Change focus shape
if (this.isOnFocus() !== focus) {
2022-11-27 21:28:32 -08:00
// Focus is always present to support on over
this._focusShape.setOpacity(focus ? 1 : 0);
this._focusShape.setStroke(focus ? 2 : 8, 'solid', '#3f96ff');
2021-10-04 17:05:34 -07:00
this._controlPointsController.setVisibility(focus);
this._onFocus = focus;
this.fireEvent(focus ? 'ontfocus' : 'ontblur', this);
2021-07-16 11:41:58 -03:00
}
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-11-27 21:28:32 -08:00
private positionRefreshShape(): void {
2021-10-04 17:05:34 -07:00
const sPos = this._line2d.getFrom();
const tPos = this._line2d.getTo();
2022-11-27 10:22:19 -08:00
2021-10-04 17:05:34 -07:00
const ctrlPoints = this._line2d.getControlPoints();
this._focusShape.setFrom(sPos.x, sPos.y);
this._focusShape.setTo(tPos.x, tPos.y);
2022-11-27 10:22:19 -08:00
this._focusShape.setSrcControlPoint(ctrlPoints[0]);
this._focusShape.setDestControlPoint(ctrlPoints[1]);
2022-11-26 08:47:35 -08:00
2021-10-04 17:05:34 -07:00
this._focusShape.updateLine();
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-01-24 11:24:16 -08:00
// @typescript-eslint/ban-types
2022-02-09 19:44:55 -08:00
addEvent(eventType: string, listener) {
let type = eventType;
2021-10-04 17:05:34 -07:00
// Translate to web 2d events ...
if (type === 'onfocus') {
2021-10-04 17:05:34 -07:00
type = 'mousedown';
}
const line = this._line2d;
line.addEvent(type, listener);
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-01-24 11:24:16 -08:00
isOnFocus(): boolean {
2021-10-04 17:05:34 -07:00
return this._onFocus;
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-01-24 11:24:16 -08:00
isInWorkspace(): boolean {
2021-10-04 17:05:34 -07:00
return this._isInWorkspace;
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-02-28 16:12:45 -08:00
setVisibility(value: boolean, fade = 0) {
super.setVisibility(value, fade);
2022-03-07 19:43:04 -08:00
// If visibility change, remove the on focus.
this.setOnFocus(false);
2022-11-27 21:28:32 -08:00
// Hide on gocus shade ...
2022-03-07 19:43:04 -08:00
if (this._showEndArrow) {
this._endArrow.setVisibility(this._showEndArrow);
}
2022-02-28 16:12:45 -08:00
this._startArrow.setVisibility(this._showStartArrow && value, fade);
2022-11-27 21:28:32 -08:00
this._focusShape.setVisibility(value);
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-03-07 19:43:04 -08:00
setOpacity(opacity: number): void {
2021-12-05 09:25:16 -08:00
super.setOpacity(opacity);
2022-03-07 19:43:04 -08:00
if (this._showEndArrow) {
this._endArrow.setOpacity(opacity);
}
if (this._showStartArrow) {
this._startArrow.setOpacity(opacity);
}
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-01-24 11:24:16 -08:00
setShowEndArrow(visible: boolean) {
2021-10-04 17:05:34 -07:00
this._showEndArrow = visible;
2022-03-07 19:43:04 -08:00
if (this._isInWorkspace) {
this.redraw();
}
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-11-27 10:22:19 -08:00
setShowStartArrow(visible: boolean): void {
2021-10-04 17:05:34 -07:00
this._showStartArrow = visible;
if (this._isInWorkspace) this.redraw();
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-11-27 10:22:19 -08:00
setFrom(x: number, y: number): void {
2021-10-04 17:05:34 -07:00
$assert($defined(x), 'x must be defined');
$assert($defined(y), 'y must be defined');
this._line2d.setFrom(x, y);
this._startArrow.setFrom(x, y);
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-01-24 11:24:16 -08:00
setTo(x: number, y: number) {
2021-10-04 17:05:34 -07:00
$assert($defined(x), 'x must be defined');
$assert($defined(y), 'y must be defined');
this._line2d.setTo(x, y);
if (this._endArrow) this._endArrow.setFrom(x, y);
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-03-07 19:43:04 -08:00
setSrcControlPoint(control: PositionType): void {
2021-10-04 17:05:34 -07:00
this._line2d.setSrcControlPoint(control);
2022-11-27 10:22:19 -08:00
this._focusShape.setSrcControlPoint(control);
2021-10-04 17:05:34 -07:00
this._startArrow.setControlPoint(control);
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-03-07 19:43:04 -08:00
setDestControlPoint(control: PositionType) {
2021-10-04 17:05:34 -07:00
this._line2d.setDestControlPoint(control);
2022-11-27 10:22:19 -08:00
this._focusShape.setSrcControlPoint(control);
if (this._showEndArrow) {
this._endArrow.setControlPoint(control);
}
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-03-07 19:43:04 -08:00
getControlPoints(): PositionType {
2021-10-04 17:05:34 -07:00
return this._line2d.getControlPoints();
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-03-07 19:43:04 -08:00
isSrcControlPointCustom(): boolean {
2021-10-04 17:05:34 -07:00
return this._line2d.isSrcControlPointCustom();
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-03-07 19:43:04 -08:00
isDestControlPointCustom(): boolean {
2021-10-04 17:05:34 -07:00
return this._line2d.isDestControlPointCustom();
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-01-24 11:24:16 -08:00
setIsSrcControlPointCustom(isCustom: boolean) {
2021-10-04 17:05:34 -07:00
this._line2d.setIsSrcControlPointCustom(isCustom);
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-01-24 11:24:16 -08:00
setIsDestControlPointCustom(isCustom: boolean) {
2021-10-04 17:05:34 -07:00
this._line2d.setIsDestControlPointCustom(isCustom);
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-03-07 19:43:04 -08:00
getId(): number {
2021-10-04 17:05:34 -07:00
return this._model.getId();
2021-12-04 15:39:20 -08:00
}
2021-10-04 17:05:34 -07:00
2022-02-11 22:42:47 -08:00
fireEvent(type: string, event): void {
2021-10-04 17:05:34 -07:00
const elem = this._line2d;
elem.trigger(type, event);
2021-12-04 15:39:20 -08:00
}
2021-07-16 11:41:58 -03:00
2022-01-24 11:24:16 -08:00
static getStrokeColor() {
return '#9b74e6';
}
}
2021-07-16 11:41:58 -03:00
export default Relationship;