/* * ******************************************************************************************************************** * * :*$@@%$*: ;: ;; ;; * :@@%! :!@@%: %! ;%%@@%$ =@@@@@@@%; @%@@@%%%%@@@@@ * :@%; :$= %%$$$%$$ ;$$ ;$@= !@$ * =@! %! @ $=;% !@@@%: !$$$$$$$$$$$$$$= * =@* %! @ $= % %@= =%@! %= * *$%%! @@= ;=$%%%$*: %! @ $= % =%%%%%%@$ *%: =% * %@@!: !@@@%=$@@@@%! :*@@$: %! @ $= % $* ;@ @* :%* * ;@@! ;!!!;: ;@%: =======@%========* @ $$ % $%*****$@ :@$=*********=@$ * $@* ;@@@%=!: *@* * =@$ ;;;!=%@@@@=! =@! * %@$: =@%: :*@@@* %@= Copyright (c) 2016-2019. 北京上格云技术有限公司 * ;%@@$=$@@%* *@@@$=%@@%; * ::;:: ::;:: All rights reserved. * * ******************************************************************************************************************** */ import { SGraphItem, SGraphPointListInsert, SGraphPointListDelete, SGraphPointListUpdate } from "@saga-web/graph/lib"; import { SUndoStack } from "@saga-web/base/"; ; import { SColor, SLineCapStyle, SPoint, SRect, SLine, SPolygonUtil } from "@saga-web/draw"; import { SMathUtil } from "@saga-web/big/lib/utils/SMathUtil"; import { SItemStatus } from "@saga-web/big"; /** * 编辑多边形 * * @author 韩耀龙 */ export class SPolygonItem extends SGraphItem { /** * 构造函数 * * @param parent 指向父对象 * @param data PolygonData数据 */ constructor(parent) { super(parent); /** X坐标最小值 */ this.minX = Number.MAX_SAFE_INTEGER; /** X坐标最大值 */ this.maxX = Number.MIN_SAFE_INTEGER; /** Y坐标最小值 */ this.minY = Number.MAX_SAFE_INTEGER; /** Y坐标最大值 */ this.maxY = Number.MIN_SAFE_INTEGER; /** 轮廓线坐标 */ this.pointList = []; /** 是否闭合 */ this.closeFlag = false; // 当前状态 this._status = SItemStatus.Normal; this.data = null; /** 边框颜色 */ this._strokeColor = new SColor("#0091FF"); /** 填充颜色 */ this._fillColor = new SColor("#1EE887"); /** 边框的宽 只可输入像素宽*/ this._lineWidth = 4; /** 鼠标移动点 */ this.lastPoint = null; /** 当前鼠标获取顶点对应索引 */ this.curIndex = -1; /** 当前鼠标获取顶点对应坐标 */ this.curPoint = null; /** 灵敏像素 */ this.len = 10; /** 场景像素 内部将灵敏像素换算为场景实际距离 */ this.scenceLen = 15; /** 场景像素 */ this.isAlt = false; /** undoredo堆栈 */ this.undoStack = new SUndoStack(); } // 获取当前状态 get getPointList() { return this.pointList; } // 编辑当前状态 set setPointList(arr) { this.pointList = arr; this.update(); } ; // 获取当前状态 get status() { return this._status; } // 编辑当前状态 set status(value) { this._status = value; // 如果状态为show则需清栈 if (value == SItemStatus.Normal) { if (this.undoStack) { this.undoStack.clear(); } } this.update(); } ; /** 画笔颜色 */ get strokeColor() { return this._strokeColor; } ; set strokeColor(v) { this._strokeColor = v; } get fillColor() { return this._fillColor; } ; set fillColor(v) { this._fillColor = v; } get lineWidth() { return this._lineWidth; } set lineWidth(v) { this._lineWidth = v; this.update(); } ; ////////////////// // 以下为对pointList 数组的操作方法 /** * 储存新的多边形顶点 * * @param x 点位得x坐标 * @param y 点位得y坐标 * @param i 储存所在索引 * @return SPoint。添加的顶点 */ insertPoint(x, y, i = null) { const point = new SPoint(x, y); if (i == null) { this.pointList.push(point); } else { this.pointList.splice(i, 0, point); } this.update(); return point; } /** * 删除点位 * * @param i 删除点所在的索引 * @return SPoint|null。索引不在数组范围则返回null */ deletePoint(i = null) { let point = null; if (i != null) { if (i >= (this.pointList.length) || i < 0) { point = null; } else { point = new SPoint(this.pointList[i].x, this.pointList[i].y); this.pointList.splice(i, 1); } } else { if (this.pointList.length) { point = this.pointList[this.pointList.length - 1]; this.pointList.pop(); } else { point = null; } } this.update(); return point; } /** * 多边形顶点的移动位置 * * @param x 点位得x坐标 * @param y 点位得y坐标 * @param i 点位得i坐标 * @return 移动对应得点。如果索引无法找到移动顶点,则返回null */ movePoint(x, y, i) { let point = null; if (i >= (this.pointList.length) || i < 0) { return null; } if (this.pointList.length) { this.pointList[i].x = x; this.pointList[i].y = y; } point = this.pointList[i]; return point; } /** * 打印出多边形数组 * * @return 顶点数组 */ PrintPointList() { return this.pointList; } //////////// // 以下为三种状态下的绘制多边形方法 /** * 展示状态 --绘制多边形数组 * * @param painter 绘制类 * @param pointList 绘制多边形数组 */ drawShowPolygon(painter, pointList) { painter.pen.lineCapStyle = SLineCapStyle.Square; painter.pen.color = this._strokeColor; painter.pen.lineWidth = painter.toPx(this._lineWidth); painter.brush.color = this._fillColor; painter.drawPolygon([...pointList]); } /** * 创建状态 --绘制多边形数组 * * @param painter 绘制类 * @param pointList 绘制多边形数组 */ drawCreatePolygon(painter, pointList) { painter.pen.lineCapStyle = SLineCapStyle.Square; painter.pen.color = this._strokeColor; painter.pen.lineWidth = painter.toPx(this._lineWidth); if (this.lastPoint && pointList.length) { painter.drawLine(pointList[pointList.length - 1].x, pointList[pointList.length - 1].y, this.lastPoint.x, this.lastPoint.y); } painter.drawPolyline(pointList); painter.pen.color = SColor.Transparent; painter.brush.color = this._fillColor; painter.pen.lineWidth = painter.toPx(this._lineWidth); if (this.lastPoint) { painter.drawPolygon([...pointList, this.lastPoint]); } else { painter.drawPolygon(pointList); } } /** * * 编辑状态 --绘制多边形数组 * * @param painter 绘制类 * @param pointList 绘制多边形数组 */ drawEditPolygon(painter, pointList) { // 展示多边形 this.drawShowPolygon(painter, pointList); // 绘制顶点块 painter.pen.color = SColor.Black; painter.brush.color = SColor.White; pointList.forEach((item, index) => { painter.drawCircle(item.x, item.y, painter.toPx(this.len / 2)); }); } /** * 编辑状态操作多边形数组 * * @param event 鼠标事件 * * */ editPolygonPoint(event) { // 判断是否为删除状态 isAlt = true为删除状态 if (this.isAlt) { // 1 判断是否点击在多边形顶点 let lenIndex = -1; // 当前点击到的点位索引; let curenLen = this.scenceLen; // 当前的灵敏度 this.pointList.forEach((item, index) => { let dis = SMathUtil.pointDistance(event.x, event.y, item.x, item.y); if (dis < curenLen) { curenLen = dis; lenIndex = index; } }); // 若点击到,对该索引对应的点做删除 if (lenIndex != -1) { if (this.pointList.length <= 3) { return; } const delePoint = new SPoint(this.pointList[lenIndex].x, this.pointList[lenIndex].y); this.deletePoint(lenIndex); // 记录顶点操作记录压入堆栈 this.recordAction(SGraphPointListDelete, [this.pointList, delePoint, lenIndex]); } } else { // 1 判断是否点击在多边形顶点 this.curIndex = -1; this.curPoint = null; let lenIndex = -1; // 当前点击到的点位索引; let curenLen = this.scenceLen; // 当前的灵敏度 this.pointList.forEach((item, index) => { let dis = SMathUtil.pointDistance(event.x, event.y, item.x, item.y); if (dis < curenLen) { curenLen = dis; lenIndex = index; } }); this.curIndex = lenIndex; // 2判断是否点击在多边形得边上 if (-1 == lenIndex) { let len = SMathUtil.pointToLine(new SPoint(event.x, event.y), new SLine(this.pointList[0], this.pointList[1])), index = 0; if (this.pointList.length > 2) { for (let i = 1; i < this.pointList.length; i++) { let dis = SMathUtil.pointToLine(new SPoint(event.x, event.y), new SLine(this.pointList[i], this.pointList[i + 1])); if ((i + 1) == this.pointList.length) { dis = SMathUtil.pointToLine(new SPoint(event.x, event.y), new SLine(this.pointList[i], this.pointList[0])); } if (dis.MinDis < len.MinDis) { len = dis; index = i; } } } // 判断是否有点 if (len.Point) { console.log(index, len.Point); // 点在了多边形的边上 if (len.MinDis <= this.scenceLen) { this.pointList.splice(index + 1, 0, len.Point); // 记录新增顶点操作记录压入堆栈 this.recordAction(SGraphPointListInsert, [this.pointList, len.Point, index + 1]); } else { //没点在多边形边上也没点在多边形顶点上 super.onMouseDown(event); } } } else { // 当捕捉到顶点后 ,记录当前点的xy坐标,用于undo、redo操作 this.curPoint = new SPoint(this.pointList[this.curIndex].x, this.pointList[this.curIndex].y); } // 刷新视图 this.update(); } } ///////////////////// // undo、redo相关操作 /** * 记录相关动作并推入栈中 * @param SGraphCommand 相关命令类 * @param any 对应传入参数 */ recordAction(SGraphCommand, any) { // 记录相关命令并推入堆栈中 const sgraphcommand = new SGraphCommand(this, ...any); if (this.undoStack) { this.undoStack.push(sgraphcommand); } } /** * 执行取消操作执行 */ undo() { if (this.status == SItemStatus.Normal) { return; } if (this.undoStack) { this.undoStack.undo(); } } /** * 执行重做操作执行 */ redo() { if (this.status == SItemStatus.Normal) { return; } if (this.undoStack) { this.undoStack.redo(); } } /////////////////////////////// // 以下为鼠标事件 /** * 鼠标双击事件 * * @param event 事件参数 * @return boolean */ onDoubleClick(event) { // 如果位show状态 双击改对象则需改为编辑状态 if (SItemStatus.Normal == this.status) { this.status = SItemStatus.Edit; this.grabItem(this); } else if (SItemStatus.Edit == this.status) { this.status = SItemStatus.Normal; this.releaseItem(); if (this.undoStack) { this.undoStack.clear(); } } this.update(); return true; } // Function onDoubleClick() /** * 键盘事件 * * @param event 事件参数 * @return boolean */ onKeyDown(event) { if (this.status == SItemStatus.Normal) { return false; } else if (this.status == SItemStatus.Create) { if (event.code == 'Enter') { // 当顶点大于二个时才又条件执行闭合操作并清空堆栈 if (this.pointList.length > 2) { this.status = SItemStatus.Normal; //3 传递完成事件状态 this.$emit('finishCreated'); //1 grabItem 置为null this.releaseItem(); //2 清空undo if (this.undoStack) { this.undoStack.clear(); } } } } else if (this.status == SItemStatus.Edit) { if (event.key == 'Alt') { this.isAlt = true; } } this.update(); return true; } // Function onKeyDown() /** * 键盘键抬起事件 * * @param event 事件参数 * @return boolean */ onKeyUp(event) { if (this.status == SItemStatus.Edit) { if (event.key == 'Alt') { this.isAlt = false; } } this.update(); } // Function onKeyUp() /** * 鼠标按下事件 * * @param event 事件参数 * @return boolean */ onMouseDown(event) { // 如果状态为编辑状态则添加点 if (this.status == SItemStatus.Create) { // 新增顶点 this.insertPoint(event.x, event.y); // 记录新增顶点操作记录压入堆栈 let pos = new SPoint(event.x, event.y); this.recordAction(SGraphPointListInsert, [this.pointList, pos]); } else if (this.status == SItemStatus.Edit) { // 对多边形数组做编辑操作 this.editPolygonPoint(event); } else { return super.onMouseDown(event); } return true; } // Function onMouseDown() /** * 鼠标移入事件 * * @param event 事件参数 * @return boolean */ onMouseEnter(event) { return true; } // Function onMouseEnter() /** * 鼠标移出事件 * * @param event 事件参数 * @return boolean */ onMouseLeave(event) { return true; } // Function onMouseLeave() /** * 鼠标移动事件 * * @param event 事件参数 * @return boolean */ onMouseMove(event) { if (this.status == SItemStatus.Create) { this.lastPoint = new SPoint; this.lastPoint.x = event.x; this.lastPoint.y = event.y; this.update(); } else if (this.status == SItemStatus.Edit) { if (-1 != this.curIndex) { this.pointList[this.curIndex].x = event.x; this.pointList[this.curIndex].y = event.y; } this.update(); } else { // return super.onMouseMove(event) } return true; } // Function onMouseMove() /** * 鼠标抬起事件 * * @param event 事件参数 * @return boolean */ onMouseUp(event) { if (this.status == SItemStatus.Edit) { if (-1 != this.curIndex) { const pos = new SPoint(this.pointList[this.curIndex].x, this.pointList[this.curIndex].y); this.recordAction(SGraphPointListUpdate, [this.pointList, this.curPoint, pos, this.curIndex]); } this.curIndex = -1; this.curPoint = null; } else { // return super.onMouseUp(event) } return true; } // Function onMouseUp() /** * 适配事件 * * @param event 事件参数 * @return boolean */ onResize(event) { return true; } // Function onResize() /** * 取消操作 * * @param painter painter对象 */ cancelOperate() { // 当状态为展示状态 if (this.status == SItemStatus.Create) { // 闭合多边形 this.parent = null; } else if (this.status == SItemStatus.Edit) { // 编辑状态 this.status = SItemStatus.Normal; } this.update(); } // Function cancelOperate() /** * Item对象边界区域 * * @return SRect */ boundingRect() { if (this.pointList.length) { this.minX = this.pointList[0].x; this.maxX = this.pointList[0].x; this.minY = this.pointList[0].y; this.maxY = this.pointList[0].y; this.pointList.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() /** * 判断点是否在区域内 * * @param x * @param y */ contains(x, y) { let arr = this.pointList; if (arr.length < 3 || !SPolygonUtil.pointIn(x, y, arr)) { return false; } return true; } // Function contains() /** * Item绘制操作 * * @param painter painter对象 */ onDraw(painter) { this.scenceLen = painter.toPx(this.len); // 当状态为展示状态 if (this.status == SItemStatus.Normal) { // 闭合多边形 this.drawShowPolygon(painter, this.pointList); } else if (this.status == SItemStatus.Create) { // 创建状态 this.drawCreatePolygon(painter, this.pointList); } else { // 编辑状态 this.drawEditPolygon(painter, this.pointList); } } // Function onDraw() }