devexpress-diagram
Version:
DevExpress Diagram Control
164 lines (152 loc) • 8.45 kB
text/typescript
import { Point } from "@devexpress/utils/lib/geometry/point";
import { History } from "../../History/History";
import { Connector } from "../../Model/Connectors/Connector";
import { ConnectionPointSide, DiagramItem, ItemKey } from "../../Model/DiagramItem";
import { DiagramModel } from "../../Model/Model";
import { ModelUtils } from "../../Model/ModelUtils";
import { DiagramMouseEvent } from "../Event";
import { MouseHandler } from "../MouseHandler";
import { MouseHandlerDraggingState } from "./MouseHandlerDraggingState";
import { GeometryUtils } from "../../Utils";
import { ConnectorRenderPoint } from "../../Model/Connectors/ConnectorRenderPoint";
export class MouseHandlerMoveConnectorOrthogonalSideState extends MouseHandlerDraggingState {
startPoint: Point;
connector: Connector;
canCreatePoints: boolean = true;
leftRenderPointIndex: number;
rightRenderPointIndex: number;
isHorizontal: boolean;
leftPointIndex: number;
rightPointIndex: number;
constructor(handler: MouseHandler, history: History, protected model: DiagramModel) {
super(handler, history);
}
private saveSidePoints(markLeftRenderPointIndex: number, markRightRenderPointIndex: number): void {
const renderPoints = this.connector.getRenderPoints(true);
this.isHorizontal = renderPoints[markLeftRenderPointIndex].y === renderPoints[markRightRenderPointIndex].y;
this.iterateRenderPoints(renderPoints, markLeftRenderPointIndex, false,
(pt, i) => {
if(pt.pointIndex !== -1)
this.leftPointIndex = pt.pointIndex;
this.leftRenderPointIndex = i;
},
(pt) => !GeometryUtils.arePointsOfOrthogonalLine(renderPoints[markLeftRenderPointIndex], pt, this.isHorizontal));
this.iterateRenderPoints(renderPoints, this.leftRenderPointIndex, true,
(pt, i) => {
if(pt.pointIndex !== -1)
this.rightPointIndex = pt.pointIndex;
this.rightRenderPointIndex = i;
},
(pt) => !GeometryUtils.arePointsOfOrthogonalLine(renderPoints[markLeftRenderPointIndex], pt, this.isHorizontal));
}
private iterateRenderPoints(renderPoints: ConnectorRenderPoint[], startIndex: number, direction: boolean, callback: (renderPoint: ConnectorRenderPoint, index: number) => void, stopPredicate?: (renderPoint: ConnectorRenderPoint, index: number) => boolean) {
for(let i = startIndex; direction ? i < renderPoints.length : i >= 0; direction ? i++ : i--) {
const point = renderPoints[i];
if(stopPredicate && stopPredicate(point, i)) break;
callback(point, i);
}
}
onMouseDown(evt: DiagramMouseEvent): void {
this.startPoint = evt.modelPoint;
this.connector = this.model.findConnector(evt.source.key);
this.handler.addInteractingItem(this.connector);
const renderPointIndexes = evt.source.value.split("_");
this.saveSidePoints(parseInt(renderPointIndexes[0]), parseInt(renderPointIndexes[1]));
super.onMouseDown(evt);
}
private shouldCreatePoint(isLeft: boolean): boolean {
if(!this.canCreatePoints) return false;
if(isLeft && (this.leftPointIndex === undefined || this.leftPointIndex === 0)) return true;
if(!isLeft && (this.rightPointIndex === undefined || this.rightPointIndex === this.connector.points.length - 1)) return true;
const renderPoints = this.connector.getRenderPoints(true);
if(isLeft && !this.connector.points[this.leftPointIndex].equals(renderPoints[this.leftRenderPointIndex])) return true;
if(!isLeft && !this.connector.points[this.rightPointIndex].equals(renderPoints[this.rightRenderPointIndex])) return true;
return false;
}
onApplyChanges(evt: DiagramMouseEvent): void {
if(this.shouldCreatePoint(true) || this.shouldCreatePoint(false)) {
let renderPoints = this.connector.getRenderPoints(true);
const leftRenderPoint = renderPoints[this.leftRenderPointIndex];
const rightRenderPoint = renderPoints[this.rightRenderPointIndex];
if(this.shouldCreatePoint(true)) {
const leftPoint = new Point(leftRenderPoint.x, leftRenderPoint.y);
if(this.leftPointIndex === 0) {
this.leftPointIndex = 1;
this.correctEdgePoint(leftPoint, rightRenderPoint, this.connector.beginItem, this.connector.beginConnectionPointIndex);
}
else if(this.leftPointIndex === undefined)
this.iterateRenderPoints(renderPoints, this.leftRenderPointIndex, true,
pt => {
if(pt.pointIndex !== -1)
this.leftPointIndex = pt.pointIndex;
},
() => this.leftPointIndex !== undefined);
ModelUtils.addConnectorPoint(this.history, this.connector.key, this.leftPointIndex, leftPoint);
if(this.rightPointIndex !== undefined)
this.rightPointIndex++;
}
if(this.shouldCreatePoint(false)) {
renderPoints = this.connector.getRenderPoints(true);
const rightPoint = new Point(rightRenderPoint.x, rightRenderPoint.y);
if(this.rightPointIndex === this.connector.points.length - 1) {
this.correctEdgePoint(rightPoint, leftRenderPoint, this.connector.endItem, this.connector.endConnectionPointIndex);
this.rightPointIndex--;
}
else if(this.rightPointIndex === undefined)
this.iterateRenderPoints(renderPoints, this.rightRenderPointIndex, false,
pt => {
if(pt.pointIndex !== -1)
this.rightPointIndex = pt.pointIndex;
},
() => this.rightPointIndex === this.leftPointIndex);
this.rightPointIndex++;
ModelUtils.addConnectorPoint(this.history, this.connector.key, this.rightPointIndex, rightPoint);
}
}
this.canCreatePoints = false;
const point = this.getSnappedPoint(evt, evt.modelPoint);
ModelUtils.moveConnectorRightAnglePoints(this.history, this.connector, this.leftPointIndex, this.rightPointIndex,
this.isHorizontal ? undefined : point.x,
this.isHorizontal ? point.y : undefined);
this.handler.tryUpdateModelSize();
}
onFinishWithChanges(): void {
ModelUtils.deleteConnectorUnnecessaryPoints(this.history, this.connector);
ModelUtils.fixConnectorBeginEndConnectionIndex(this.history, this.connector);
this.handler.tryUpdateModelSize();
}
correctEdgePoint(point: Point, directionPoint: Point, item: DiagramItem, connectionPointIndex: number): void {
let offset = 0;
if(item) {
const side = item.getConnectionPointSideByIndex(connectionPointIndex);
const rect = item.rectangle;
offset = Connector.minOffset;
switch(side) {
case ConnectionPointSide.South:
offset += rect.bottom - point.y;
break;
case ConnectionPointSide.North:
offset += point.y - rect.y;
break;
case ConnectionPointSide.East:
offset += rect.right - point.x;
break;
case ConnectionPointSide.West:
offset += point.x - rect.x;
break;
}
}
if(this.isHorizontal)
if(point.x > directionPoint.x)
point.x -= Math.min(offset, point.x - directionPoint.x);
else
point.x += Math.min(offset, directionPoint.x - point.x);
else if(point.y > directionPoint.y)
point.y -= Math.min(offset, point.y - directionPoint.y);
else
point.y += Math.min(offset, directionPoint.y - point.y);
}
getDraggingElementKeys(): ItemKey[] {
return [this.connector.key];
}
}