sprotty
Version:
A next-gen framework for graphical views
167 lines • 8.33 kB
JavaScript
;
/********************************************************************************
* Copyright (c) 2019 TypeFox and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var PolylineEdgeRouter_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PolylineEdgeRouter = void 0;
const inversify_1 = require("inversify");
const geometry_1 = require("sprotty-protocol/lib/utils/geometry");
const model_1 = require("./model");
const anchor_1 = require("./anchor");
const abstract_edge_router_1 = require("./abstract-edge-router");
let PolylineEdgeRouter = PolylineEdgeRouter_1 = class PolylineEdgeRouter extends abstract_edge_router_1.AbstractEdgeRouter {
get kind() {
return PolylineEdgeRouter_1.KIND;
}
getOptions(edge) {
return {
minimalPointDistance: 2,
removeAngleThreshold: 0.1,
standardDistance: 20,
selfEdgeOffset: 0.25
};
}
route(edge) {
const source = edge.source;
const target = edge.target;
if (source === undefined || target === undefined) {
return [];
}
let sourceAnchor;
let targetAnchor;
const options = this.getOptions(edge);
const routingPoints = edge.routingPoints.length > 0
? edge.routingPoints
: [];
this.cleanupRoutingPoints(edge, routingPoints, false, false);
const rpCount = routingPoints !== undefined ? routingPoints.length : 0;
if (rpCount === 0) {
// Use the target center as start anchor reference
const startRef = geometry_1.Bounds.center(target.bounds);
sourceAnchor = this.getTranslatedAnchor(source, startRef, target.parent, edge, edge.sourceAnchorCorrection);
// Use the source center as end anchor reference
const endRef = geometry_1.Bounds.center(source.bounds);
targetAnchor = this.getTranslatedAnchor(target, endRef, source.parent, edge, edge.targetAnchorCorrection);
}
else {
// Use the first routing point as start anchor reference
const p0 = routingPoints[0];
sourceAnchor = this.getTranslatedAnchor(source, p0, edge.parent, edge, edge.sourceAnchorCorrection);
// Use the last routing point as end anchor reference
const pn = routingPoints[rpCount - 1];
targetAnchor = this.getTranslatedAnchor(target, pn, edge.parent, edge, edge.targetAnchorCorrection);
}
const result = [];
result.push({ kind: 'source', x: sourceAnchor.x, y: sourceAnchor.y });
for (let i = 0; i < rpCount; i++) {
const p = routingPoints[i];
if (i > 0 && i < rpCount - 1
|| i === 0 && geometry_1.Point.maxDistance(sourceAnchor, p) >= options.minimalPointDistance + (edge.sourceAnchorCorrection || 0)
|| i === rpCount - 1 && geometry_1.Point.maxDistance(p, targetAnchor) >= options.minimalPointDistance + (edge.targetAnchorCorrection || 0)) {
result.push({ kind: 'linear', x: p.x, y: p.y, pointIndex: i });
}
}
result.push({ kind: 'target', x: targetAnchor.x, y: targetAnchor.y });
return this.filterEditModeHandles(result, edge, options);
}
/**
* Remove routed points that are in edit mode and for which the angle between the preceding and
* following points falls below a threshold.
*/
filterEditModeHandles(route, edge, options) {
if (edge.children.length === 0)
return route;
let i = 0;
while (i < route.length) {
const curr = route[i];
if (curr.pointIndex !== undefined) {
const handle = edge.children.find(child => child instanceof model_1.SRoutingHandleImpl && child.kind === 'junction' && child.pointIndex === curr.pointIndex);
if (handle !== undefined && handle.editMode && i > 0 && i < route.length - 1) {
const prev = route[i - 1], next = route[i + 1];
const prevDiff = { x: prev.x - curr.x, y: prev.y - curr.y };
const nextDiff = { x: next.x - curr.x, y: next.y - curr.y };
const angle = (0, geometry_1.angleBetweenPoints)(prevDiff, nextDiff);
if (Math.abs(Math.PI - angle) < options.removeAngleThreshold) {
route.splice(i, 1);
continue;
}
}
}
i++;
}
return route;
}
createRoutingHandles(edge) {
const rpCount = edge.routingPoints.length;
this.addHandle(edge, 'source', 'routing-point', -2);
this.addHandle(edge, 'line', 'volatile-routing-point', -1);
for (let i = 0; i < rpCount; i++) {
this.addHandle(edge, 'junction', 'routing-point', i);
this.addHandle(edge, 'line', 'volatile-routing-point', i);
}
this.addHandle(edge, 'target', 'routing-point', rpCount);
}
getInnerHandlePosition(edge, route, handle) {
if (handle.kind === 'line') {
const { start, end } = this.findRouteSegment(edge, route, handle.pointIndex);
if (start !== undefined && end !== undefined)
return (0, geometry_1.centerOfLine)(start, end);
}
return undefined;
}
applyInnerHandleMoves(edge, moves) {
moves.forEach(move => {
const handle = move.handle;
const points = edge.routingPoints;
let index = handle.pointIndex;
if (handle.kind === 'line') {
// Upgrade to a proper routing point
handle.kind = 'junction';
handle.type = 'routing-point';
points.splice(index + 1, 0, move.fromPosition || points[Math.max(index, 0)]);
edge.children.forEach(child => {
if (child instanceof model_1.SRoutingHandleImpl && (child === handle || child.pointIndex > index))
child.pointIndex++;
});
this.addHandle(edge, 'line', 'volatile-routing-point', index);
index++;
this.addHandle(edge, 'line', 'volatile-routing-point', index);
}
if (index >= 0 && index < points.length) {
points[index] = move.toPosition;
}
});
}
};
exports.PolylineEdgeRouter = PolylineEdgeRouter;
PolylineEdgeRouter.KIND = 'polyline';
__decorate([
(0, inversify_1.inject)(anchor_1.AnchorComputerRegistry),
__metadata("design:type", anchor_1.AnchorComputerRegistry)
], PolylineEdgeRouter.prototype, "anchorRegistry", void 0);
exports.PolylineEdgeRouter = PolylineEdgeRouter = PolylineEdgeRouter_1 = __decorate([
(0, inversify_1.injectable)()
], PolylineEdgeRouter);
//# sourceMappingURL=polyline-edge-router.js.map