UNPKG

devexpress-diagram

Version:

DevExpress Diagram Control

179 lines (173 loc) 11.4 kB
import { Point } from "@devexpress/utils/lib/geometry/point"; import { Segment } from "@devexpress/utils/lib/geometry/segment"; import { DiagramItem } from "../../../DiagramItem"; import { ConnectorRenderPoint } from "../../ConnectorRenderPoint"; import { IConnectorRoutingModel, IConnectorRoutingStrategy } from "../ConnectorRoutingModel"; import { ConnectorRenderSegment } from "../ConnectorRenderSegment"; import { IConnectorRoutingContext, RightAngleConnectorRoutingContext } from "./RightAngleConnectorRoutingContext"; import { ModelUtils } from "../../../ModelUtils"; export class RightAngleConnectorRoutingStrategy implements IConnectorRoutingStrategy { constructor(private readonly model: IConnectorRoutingModel) { } createRenderPoints(points: Point[], supportRenderPoints: ConnectorRenderPoint[], beginConnectionShape: DiagramItem, endConnectionShape: DiagramItem, beginConnectionPointIndex: number, endConnectionPointIndex: number, container: DiagramItem): ConnectorRenderPoint[] { if(supportRenderPoints.length > 1) { const context = new RightAngleConnectorRoutingContext( this.model, points, supportRenderPoints, beginConnectionShape, endConnectionShape, beginConnectionPointIndex, endConnectionPointIndex); context.initialize(container); if(context.shouldCreateRenderPoints) return this.createRenderPointsCore(context); } } clone(): IConnectorRoutingStrategy { return new RightAngleConnectorRoutingStrategy(this.model); } onAddPoint(points: Point[], pointIndex: number, point: Point, oldRenderPoints: ConnectorRenderPoint[]): ConnectorRenderPoint[] { const renderPoints = oldRenderPoints.map(p => new ConnectorRenderPoint(p.x, p.y, p.pointIndex)); const renderPointIndex = ModelUtils.findFirstPointIndex(renderPoints, p => p.equals(point)); if(renderPointIndex === 0) { renderPoints.splice(1, 0, new ConnectorRenderPoint(point.x, point.y, pointIndex)); return ModelUtils.validateRenderPointIndexes(points, renderPoints, 2); } const lastRenderPointIndex = renderPoints.length - 1; if(renderPointIndex === lastRenderPointIndex) { renderPoints.splice(lastRenderPointIndex, 0, new ConnectorRenderPoint(point.x, point.y, pointIndex)); renderPoints[lastRenderPointIndex + 1].pointIndex = pointIndex + 1; return renderPoints; } if(renderPointIndex > 0) { const oldRenderPoint = renderPoints[renderPointIndex]; renderPoints[renderPointIndex] = new ConnectorRenderPoint(oldRenderPoint.x, oldRenderPoint.y, pointIndex, oldRenderPoint.skipped); return ModelUtils.validateRenderPointIndexes(points, renderPoints, renderPointIndex + 1); } const firstSegment = new Segment(renderPoints[0], renderPoints[1]); const newRenderPoint = new ConnectorRenderPoint(point.x, point.y); if(firstSegment.containsPoint(newRenderPoint)) { renderPoints.splice(1, 0, new ConnectorRenderPoint(newRenderPoint.x, newRenderPoint.y, -1)); renderPoints.splice(2, 0, new ConnectorRenderPoint(newRenderPoint.x, newRenderPoint.y, pointIndex)); return ModelUtils.validateRenderPointIndexes(points, renderPoints, 3); } const lastSegment = new Segment(renderPoints[lastRenderPointIndex - 1], renderPoints[lastRenderPointIndex]); if(lastSegment.containsPoint(newRenderPoint)) { renderPoints.splice(lastRenderPointIndex, 0, new ConnectorRenderPoint(newRenderPoint.x, newRenderPoint.y, pointIndex)); renderPoints.splice(lastRenderPointIndex + 1, 0, new ConnectorRenderPoint(newRenderPoint.x, newRenderPoint.y, -1)); renderPoints[lastRenderPointIndex + 2].pointIndex = pointIndex + 1; return renderPoints; } return oldRenderPoints; } onDeletePoint(points: Point[], pointIndex: number, oldRenderPoints: ConnectorRenderPoint[]): ConnectorRenderPoint[] { const renderPoints = oldRenderPoints.map(p => new ConnectorRenderPoint(p.x, p.y, p.pointIndex)); const renderPointIndex = this.getRenderPointIndexByPointIndex(renderPoints, pointIndex); if(renderPointIndex === 1) { const previuosRenderPoint = renderPoints[0]; const currentRenderPoint = renderPoints[1]; if(previuosRenderPoint.equals(currentRenderPoint)) { renderPoints.splice(1, 1); return ModelUtils.validateRenderPointIndexes(points, renderPoints, 1); } renderPoints[1] = new ConnectorRenderPoint(currentRenderPoint.x, currentRenderPoint.y, -1, currentRenderPoint.skipped); return ModelUtils.validateRenderPointIndexes(points, renderPoints, 2); } if(renderPointIndex === 2) { const previuosRenderPoint = renderPoints[1]; const currentRenderPoint = renderPoints[2]; if(previuosRenderPoint.equals(currentRenderPoint)) { renderPoints.splice(1, 2); return ModelUtils.validateRenderPointIndexes(points, renderPoints, 1); } renderPoints[2] = new ConnectorRenderPoint(currentRenderPoint.x, currentRenderPoint.y, -1, currentRenderPoint.skipped); return ModelUtils.validateRenderPointIndexes(points, renderPoints, 3); } const lastRenderPointIndex = renderPoints.length - 1; if(renderPointIndex === lastRenderPointIndex - 1) { const currentRenderPoint = renderPoints[lastRenderPointIndex - 1]; const nextRenderPoint = renderPoints[lastRenderPointIndex]; if(currentRenderPoint.equals(nextRenderPoint)) { renderPoints.splice(lastRenderPointIndex - 1, 1); return ModelUtils.validateRenderPointIndexes(points, renderPoints, lastRenderPointIndex - 1); } renderPoints[lastRenderPointIndex - 1] = new ConnectorRenderPoint(currentRenderPoint.x, currentRenderPoint.y, -1, currentRenderPoint.skipped); return ModelUtils.validateRenderPointIndexes(points, renderPoints, lastRenderPointIndex); } if(renderPointIndex === lastRenderPointIndex - 2) { const currentRenderPoint = renderPoints[lastRenderPointIndex - 2]; const nextRenderPoint = renderPoints[lastRenderPointIndex - 1]; if(currentRenderPoint.equals(nextRenderPoint)) { renderPoints.splice(lastRenderPointIndex - 2, 2); return ModelUtils.validateRenderPointIndexes(points, renderPoints, lastRenderPointIndex - 2); } renderPoints[lastRenderPointIndex - 2] = new ConnectorRenderPoint(currentRenderPoint.x, currentRenderPoint.y, -1, currentRenderPoint.skipped); return ModelUtils.validateRenderPointIndexes(points, renderPoints, lastRenderPointIndex - 1); } const currentRenderPoint = renderPoints[renderPointIndex]; renderPoints[renderPointIndex] = new ConnectorRenderPoint(currentRenderPoint.x, currentRenderPoint.y, -1, currentRenderPoint.skipped); return ModelUtils.validateRenderPointIndexes(points, renderPoints, renderPointIndex + 1); } onMovePoint(points: Point[], pointIndex: number, point: Point, oldRenderPoints: ConnectorRenderPoint[]): ConnectorRenderPoint[] { if(pointIndex === 0 || pointIndex === points.length - 1) return oldRenderPoints; const renderPoints = oldRenderPoints.map(p => new ConnectorRenderPoint(p.x, p.y, p.pointIndex)); this.onMovePointCore(renderPoints, pointIndex, point); ModelUtils.skipUnnecessaryRightAngleRenderPoints(renderPoints); return renderPoints; } onMovePoints(points: Point[], beginPointIndex: number, beginPoint: Point, lastPointIndex: number, lastPoint: Point, oldRenderPoints: ConnectorRenderPoint[]): ConnectorRenderPoint[] { if(beginPointIndex === 0 || lastPointIndex === points.length - 1) return oldRenderPoints; const renderPoints = oldRenderPoints.map(p => new ConnectorRenderPoint(p.x, p.y, p.pointIndex)); this.onMovePointCore(renderPoints, beginPointIndex, beginPoint); this.onMovePointCore(renderPoints, lastPointIndex, lastPoint); ModelUtils.skipUnnecessaryRightAngleRenderPoints(renderPoints); return renderPoints; } private onMovePointCore(newRenderPoints: ConnectorRenderPoint[], pointIndex: number, newPoint: Point) : void { const renderPointIndex = this.getRenderPointIndexByPointIndex(newRenderPoints, pointIndex); if(renderPointIndex >= 0) { const oldRenderPoint = newRenderPoints[renderPointIndex]; newRenderPoints[renderPointIndex] = new ConnectorRenderPoint(newPoint.x, newPoint.y, pointIndex, oldRenderPoint.skipped); } } createRenderPointsCore(context: IConnectorRoutingContext<Point>): ConnectorRenderPoint[] { const result : ConnectorRenderPoint[] = []; let currentIndex = -1; let currentRenderSegment: ConnectorRenderSegment<Point>; let currentStartCustomPointIndex = -1; context.setup(); const renderSegments = context.renderSegments; const endPoint = renderSegments[renderSegments.length - 1].endPoint; const points = context.points; do { this.registerCustomPoints(result, points, currentStartCustomPointIndex + 2, renderSegments[currentIndex + 1].startPointIndex - 1); currentIndex++; currentRenderSegment = renderSegments[currentIndex]; currentStartCustomPointIndex = currentRenderSegment.startPointIndex; this.registerRenderPoints( result, context.createRoutedPoints(currentRenderSegment.startInfo, currentRenderSegment.endInfo, currentRenderSegment.createProhibitedSegments()), currentStartCustomPointIndex); } while(!currentRenderSegment.endPoint.equals(endPoint)); context.validateRenderPoints(result); return result; } private getRenderPointIndexByPointIndex(points: ConnectorRenderPoint[], index: number): number { return ModelUtils.findFirstPointIndex(points, p => p.pointIndex === index); } private registerRenderPoints(resultPath : ConnectorRenderPoint[], routedPoints: Point[], beginPointIndex: number): void { routedPoints.forEach((p, i) => { const pointIndex = i === 0 ? beginPointIndex : (i === routedPoints.length - 1 ? beginPointIndex + 1 : -1); this.registerPoint(resultPath, p, pointIndex); }); } private registerCustomPoints(resultPath : ConnectorRenderPoint[], points: Point[], startIndex: number, endIndex: number): void { for(let i = startIndex; i <= endIndex; i++) this.registerPoint(resultPath, points[i], i); } private registerPoint(resultPath : ConnectorRenderPoint[], point: Point, pointIndex: number): void { resultPath.push(new ConnectorRenderPoint(point.x, point.y, pointIndex)); } }