import { SColor, SLine, SPainter, SPoint, SRect } from "@saga-web/draw/lib"; import { SMouseButton, SMouseEvent, SUndoStack } from "@saga-web/base"; import { SMathUtil } from "../utils/SMathUtil"; import { SItemStatus } from ".."; import { SGraphItem, SGraphPointListInsert, SGraphPointListUpdate, SLineStyle } from "@saga-web/graph/lib"; /** * 直线item * * @author 张宇(taohuzy@163.com) * */ export class SLineItem extends SGraphItem { /** X坐标最小值 */ private minX = Number.MAX_SAFE_INTEGER; /** X坐标最大值 */ private maxX = Number.MIN_SAFE_INTEGER; /** Y坐标最小值 */ private minY = Number.MAX_SAFE_INTEGER; /** Y坐标最大值 */ private maxY = Number.MIN_SAFE_INTEGER; /** 线段 */ private _line: SPoint[] = []; get line(): SPoint[] { return this._line; } set line(arr: SPoint[]) { this._line = arr; this.update(); } /** 是否完成绘制 */ protected _status: SItemStatus = SItemStatus.Normal; get status(): SItemStatus { return this._status; } set status(v: SItemStatus) { this._status = v; this.update(); } /** 线条颜色 */ private _strokeColor: SColor = SColor.Black; get strokeColor(): SColor { return this._strokeColor; } set strokeColor(v: SColor) { this._strokeColor = v; this.update(); } /** 线条样式 */ private _lineStyle: SLineStyle = SLineStyle.Soild; get lineStyle(): SLineStyle { return this._lineStyle; } set lineStyle(v: SLineStyle) { this._lineStyle = v; this.update(); } /** 端点填充色 */ private _fillColor: SColor = SColor.White; get fillColor(): SColor { return this._fillColor; } set fillColor(v: SColor) { this._fillColor = v; this.update(); } /** 选中端点填充色 */ private _activeFillColor: SColor = new SColor("#2196f3"); get activeFillColor(): SColor { return this._activeFillColor; } set activeFillColor(v: SColor) { this._activeFillColor = v; this.update(); } /** 线条宽度 */ private _lineWidth: number = 1; get lineWidth(): number { return this._lineWidth; } set lineWidth(v: number) { this._lineWidth = v; this.update(); } /** 拖动灵敏度 */ dis: number = 5; /** 拖动灵敏度 */ private sceneDis: number = 5; /** 当前点索引 */ curIndex: number = -1; /** 当前点坐标 */ private curPoint: SPoint | null = null; /** undo/redo堆栈 */ private undoStack: SUndoStack | null = new SUndoStack(); /** * 构造函数 * * @param parent 父级 * */ constructor(parent: SGraphItem | null); /** * 构造函数 * * @param parent 父级 * @param line 坐标集合 * */ constructor(parent: SGraphItem | null, line: SPoint[]); /** * 构造函数 * * @param parent 父级 * @param point 第一个点坐标 * */ constructor(parent: SGraphItem | null, point: SPoint); /** * 构造函数 * * @param parent 父级 * @param l 坐标集合|第一个点坐标 * */ constructor(parent: SGraphItem | null, l?: SPoint | SPoint[]) { super(parent); if (l) { if (l instanceof SPoint) { this.line.push(l); } else { this.line = l; } } else { this.line = []; } } /** * 添加点至数组中 * * @param p 添加的点 * */ private addPoint(p: SPoint): void { if (this.line.length < 2) { this.line.push(p); this.recordAction(SGraphPointListInsert, [this.line, p]); } else { this.line[1] = p; this.recordAction(SGraphPointListInsert, [this.line, p, 1]); this.status = SItemStatus.Normal; this.releaseItem(); this.$emit("finishCreated"); } this.update(); } // Function addPoint() /** * 鼠标双击事件 * * @param event 事件参数 * @return boolean */ onDoubleClick(event: SMouseEvent): boolean { if (this.status == SItemStatus.Normal) { this.status = SItemStatus.Edit; this.grabItem(this); } else if (this.status == SItemStatus.Edit) { this.status = SItemStatus.Normal; this.releaseItem(); } this.update(); return true; } // Function onDoubleClick() /** * 鼠标按下事件 * * @param event 鼠标事件 * @return 是否处理事件 * */ onMouseDown(event: SMouseEvent): boolean { this.curIndex = -1; this.curPoint = null; if (event.buttons == SMouseButton.LeftButton) { if (this.status == SItemStatus.Normal) { return super.onMouseDown(event); } else if (this.status == SItemStatus.Edit) { // 判断是否点击到端点上(获取端点索引值) this.findNearestPoint(new SPoint(event.x, event.y)); } else if (this.status == SItemStatus.Create) { this.addPoint(new SPoint(event.x, event.y)); return true; } } return true; } // Function onMouseDown() /** * 鼠标抬起事件 * * @param event 事件参数 * @return boolean */ onMouseUp(event: SMouseEvent): boolean { if (this.status == SItemStatus.Edit) { if (this.curIndex > -1) { const p = new SPoint( this.line[this.curIndex].x, this.line[this.curIndex].y ); this.recordAction(SGraphPointListUpdate, [ this.line, this.curPoint, p, this.curIndex ]); } } else if (this.status == SItemStatus.Normal) { this.moveToOrigin(this.x, this.y); return super.onMouseUp(event); } this.curIndex = -1; this.curPoint = null; return true; } // Function onMouseUp() /** * 鼠标移动事件 * * @param event 鼠标事件 * @return 是否处理事件 * */ onMouseMove(event: SMouseEvent): boolean { if (this.status == SItemStatus.Create) { if (this.line[0] instanceof SPoint) { this.line[1] = new SPoint(event.x, event.y); } } else if (this.status == SItemStatus.Edit) { if (-1 != this.curIndex) { this.line[this.curIndex].x = event.x; this.line[this.curIndex].y = event.y; } } else { return super.onMouseMove(event); } this.update(); return true; } // Function onMouseMove() /** * 获取点击点与Point[]中的点距离最近点 * * @param p 鼠标点击点 * */ findNearestPoint(p: SPoint): void { let len = this.sceneDis; for (let i = 0; i < this.line.length; i++) { let dis = SMathUtil.pointDistance( p.x, p.y, this.line[i].x, this.line[i].y ); if (dis < len) { len = dis; this.curIndex = i; this.curPoint = this.line[this.curIndex]; } } } // Function findNearestPoint() /** * 记录相关动作并推入栈中 * * @param SGraphCommand 相关命令类 * @param any 对应传入参数 */ protected recordAction(SGraphCommand: any, any: any[]): void { // 记录相关命令并推入堆栈中 const command = new SGraphCommand(this, ...any); if (this.undoStack) { this.undoStack.push(command); } } // Function recordAction() /** * 移动后处理所有坐标,并肩原点置为场景原点 * * @param x x坐标 * @param y y坐标 * */ moveToOrigin(x: number, y: number): void { super.moveToOrigin(x, y); this.line = this.line.map(t => { t.x = t.x + x; t.y = t.y + y; return t; }); this.x = 0; this.y = 0; } // Function moveToOrigin() /** * 判断点是否在区域内 * * @param x * @param y * @return true-是 */ contains(x: number, y: number): boolean { if (this.line.length == 2) { let p = new SPoint(x, y); if ( SMathUtil.pointToLine(p, new SLine(this.line[0], this.line[1])) .MinDis < this.dis ) { return true; } } return false; } // Function contains() /** * 撤销操作 * */ undo(): void { if (this.status != SItemStatus.Normal) { if (this.undoStack) { this.undoStack.undo(); } } } // Function undo() /** * 重做操作 * */ redo(): void { if (this.status != SItemStatus.Normal) { if (this.undoStack) { this.undoStack.redo(); } } } // Function redo() /** * 取消操作item事件 * * */ cancelOperate(): void { if (this.status == SItemStatus.Create) { this.parent = null; this.releaseItem(); } else if (this.status == SItemStatus.Edit) { this.status = SItemStatus.Normal; this.releaseItem(); } } // Function cancelOperate() /** * Item对象边界区域 * * @return SRect */ boundingRect(): SRect { if (this.line.length) { this.minX = this.line[0].x; this.maxX = this.line[0].x; this.minY = this.line[0].y; this.maxY = this.line[0].y; this.line.forEach(it => { let x = it.x, y = it.y; if (x < this.minX) { this.minX = x; } if (y < this.minY) { this.minY = y; } if (x > this.maxX) { this.maxX = x; } if (y > this.maxY) { this.maxY = y; } }); } return new SRect( this.minX, this.minY, this.maxX - this.minX, this.maxY - this.minY ); } // Function boundingRect() /** * Item绘制操作 * * @param painter painter对象 */ onDraw(painter: SPainter): void { this.sceneDis = painter.toPx(this.dis); painter.pen.lineWidth = painter.toPx(this.lineWidth); painter.pen.color = this.strokeColor; if (this.line.length == 2) { // 绘制直线 painter.pen.color = new SColor(this.strokeColor); if (this.lineStyle == SLineStyle.Dashed) { painter.pen.lineDash = [ painter.toPx(this.lineWidth * 3), painter.toPx(this.lineWidth * 7) ]; } else if (this.lineStyle == SLineStyle.Dotted) { painter.pen.lineDash = [ painter.toPx(this.lineWidth), painter.toPx(this.lineWidth) ]; } if (this.selected && this.status == SItemStatus.Normal) { painter.pen.lineWidth = painter.toPx(this.lineWidth * 2); painter.shadow.shadowBlur = 10; painter.shadow.shadowColor = new SColor(`#00000033`); painter.shadow.shadowOffsetX = 5; painter.shadow.shadowOffsetY = 5; } painter.drawLine(this.line[0], this.line[1]); if ( this.status == SItemStatus.Edit || this.status == SItemStatus.Create ) { // 绘制端点 this.line.forEach((p, i): void => { painter.brush.color = this.fillColor; if (i == this.curIndex) { painter.brush.color = this.activeFillColor; } painter.drawCircle(p.x, p.y, painter.toPx(5)); }); } } else if (this.line.length == 1) { if ( this.status == SItemStatus.Edit || this.status == SItemStatus.Create ) { // 绘制端点 painter.brush.color = this.fillColor; painter.drawCircle( this.line[0].x, this.line[0].y, painter.toPx(5) ); } } } // Function onDraw() } // Class SLineItem