SPolylineItem.ts 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. import { SColor, SLine, SPainter, SPoint } from "@saga-web/draw/lib";
  2. import { SMouseEvent } from "@saga-web/base";
  3. import { SItemStatus } from "..";
  4. import { SMathUtil } from "../utils/SMathUtil";
  5. import { SGraphItem } from "@saga-web/graph/lib";
  6. /**
  7. * 直线item
  8. *
  9. * */
  10. export class SPolylineItem extends SGraphItem {
  11. /** 折点信息 */
  12. pointList: SPoint[] = [];
  13. /** 是否绘制完成 */
  14. _status: SItemStatus = SItemStatus.Create;
  15. get status(): SItemStatus {
  16. return this._status;
  17. }
  18. set status(v: SItemStatus) {
  19. this._status = v;
  20. this.update();
  21. }
  22. /** 鼠标移动时的点 */
  23. lastPoint: SPoint | null = null;
  24. /** 线条颜色 */
  25. _strokeColor: string = "#000000";
  26. get strokeColor(): string {
  27. return this._strokeColor;
  28. }
  29. set strokeColor(v: string) {
  30. this._strokeColor = v;
  31. this.update();
  32. }
  33. /** 填充色 */
  34. _fillColor: string = "#2196f3";
  35. get fillColor(): string {
  36. return this._fillColor;
  37. }
  38. set fillColor(v: string) {
  39. this._fillColor = v;
  40. this.update();
  41. }
  42. /** 线条宽度 */
  43. _lineWidth: number = 1;
  44. get lineWidth(): number {
  45. return this._lineWidth;
  46. }
  47. set lineWidth(v: number) {
  48. this._lineWidth = v;
  49. this.update();
  50. }
  51. /** 全局灵敏度 */
  52. dis: number = 10;
  53. /** 灵敏度转换为场景长度 */
  54. sceneDis: number = 10;
  55. /** 当前点索引 */
  56. curIndex: number = -1;
  57. /**
  58. * 构造函数
  59. *
  60. * @param parent 父级
  61. * @param list 坐标集合
  62. * */
  63. constructor(parent: null | SGraphItem, list: SPoint[]);
  64. /**
  65. * 构造函数
  66. *
  67. * @param parent 父级
  68. * @param list 第一个坐标
  69. * */
  70. constructor(parent: null | SGraphItem, list: SPoint);
  71. /**
  72. * 构造函数
  73. *
  74. * @param parent 父级
  75. * @param list 第一个坐标|坐标集合
  76. * */
  77. constructor(parent: null | SGraphItem, list: SPoint | SPoint[]) {
  78. super(parent);
  79. if (list instanceof SPoint) {
  80. this.pointList.push(list);
  81. } else {
  82. this.pointList = list;
  83. }
  84. } // Constructor
  85. /**
  86. * 添加点至数组中
  87. *
  88. * @param p 添加的点
  89. * @param index 添加到的索引
  90. * */
  91. private addPoint(p: SPoint, index?: number): void {
  92. if (index && this.canHandle(index)) {
  93. this.pointList.splice(index, 0, p);
  94. } else {
  95. this.pointList.push(p);
  96. }
  97. this.update();
  98. } // Function addPoint()
  99. /**
  100. * 是否可以添加点到数组中
  101. *
  102. * @param index 要添加到的索引
  103. * @return boolean 是否可添加
  104. * */
  105. private canHandle(index: number): boolean {
  106. return index >= 0 && index <= this.pointList.length;
  107. } // Function canHandle()
  108. /**
  109. * 添加点至数组中
  110. *
  111. * @param index 添加到的索引
  112. * */
  113. private delPoint(index: number): void {
  114. if (this.canHandle(index) && this.pointList.length > 2) {
  115. this.pointList.splice(index, 0);
  116. this.update();
  117. }
  118. } // Function delPoint
  119. /**
  120. * 鼠标按下事件
  121. *
  122. * @param event 鼠标事件
  123. * @return boolean 是否处理事件
  124. * */
  125. onMouseDown(event: SMouseEvent): boolean {
  126. this.curIndex = -1;
  127. if (event.buttons == 1) {
  128. if (this.status == SItemStatus.Create) {
  129. this.addPoint(new SPoint(event.x, event.y));
  130. return true;
  131. } else if (this.status == SItemStatus.Edit) {
  132. // 查询鼠标最近的索引
  133. this.findNearestPoint(new SPoint(event.x, event.y));
  134. // 增加点
  135. if (this.curIndex < 0) {
  136. this.findAddPos(new SPoint(event.x, event.y));
  137. }
  138. // 删除点
  139. if (event.altKey && this.canHandle(this.curIndex)) {
  140. this.pointList.splice(this.curIndex, 1);
  141. this.curIndex = -1;
  142. }
  143. this.update();
  144. return true;
  145. } else {
  146. return super.onMouseDown(event);
  147. }
  148. }
  149. return super.onMouseDown(event);
  150. } // Function onMouseDown()
  151. /**
  152. * 鼠标移动事件
  153. *
  154. * @param event 鼠标事件
  155. * @return boolean 是否处理事件
  156. * */
  157. onMouseMove(event: SMouseEvent): boolean {
  158. if (this.status == SItemStatus.Create) {
  159. if (this.lastPoint) {
  160. this.lastPoint.x = event.x;
  161. this.lastPoint.y = event.y;
  162. } else {
  163. this.lastPoint = new SPoint(event.x, event.y);
  164. }
  165. this.update();
  166. return true;
  167. } else if (this.status == SItemStatus.Edit) {
  168. if (this.canHandle(this.curIndex)) {
  169. this.pointList[this.curIndex].x = event.x;
  170. this.pointList[this.curIndex].y = event.y;
  171. }
  172. this.update();
  173. return true;
  174. } else {
  175. return super.onMouseMove(event);
  176. }
  177. } // Function onMouseMove()
  178. /**
  179. * 鼠标移动事件
  180. *
  181. * @param event 鼠标事件
  182. * @return boolean 是否处理事件
  183. * */
  184. onMouseUp(event: SMouseEvent): boolean {
  185. this.curIndex = -1;
  186. return true;
  187. } // Function onMouseMove()
  188. /**
  189. * 鼠标双击事件
  190. *
  191. * @param event 事件参数
  192. * @return boolean
  193. */
  194. onDoubleClick(event: SMouseEvent): boolean {
  195. if (this.status == SItemStatus.Normal) {
  196. this.status = SItemStatus.Edit;
  197. if (this.scene) {
  198. this.scene.grabItem = this;
  199. }
  200. } else if (this.status == SItemStatus.Edit) {
  201. this.status = SItemStatus.Normal;
  202. if (this.scene) {
  203. this.scene.grabItem = null;
  204. }
  205. } else if (this.status == SItemStatus.Create) {
  206. this.status = SItemStatus.Edit;
  207. }
  208. this.$emit("onDoubleClick", event);
  209. return true;
  210. } // Function onDoubleClick()
  211. /***
  212. * 键盘按键弹起事件
  213. *
  214. * @param event 事件参数
  215. */
  216. onKeyUp(event: KeyboardEvent): void {
  217. if (event.keyCode == 13) {
  218. this.status = SItemStatus.Edit;
  219. }
  220. } // Function onKeyUp()
  221. /**
  222. * 获取点击点与点集中距离最近点
  223. *
  224. * @param p 鼠标点击点
  225. * */
  226. findNearestPoint(p: SPoint): void {
  227. let len = this.sceneDis;
  228. for (let i = 0; i < this.pointList.length; i++) {
  229. let dis = SMathUtil.pointDistance(
  230. p.x,
  231. p.y,
  232. this.pointList[i].x,
  233. this.pointList[i].y
  234. );
  235. if (dis < len) {
  236. len = dis;
  237. this.curIndex = i;
  238. }
  239. }
  240. } // Function findNearestPoint()
  241. /**
  242. * 计算增加点的位置
  243. *
  244. * @param p 鼠标点击点
  245. * */
  246. findAddPos(p: SPoint): void {
  247. let len = SMathUtil.pointToLine(
  248. p,
  249. new SLine(this.pointList[0], this.pointList[1])
  250. ),
  251. index = 0;
  252. if (this.pointList.length > 2) {
  253. for (let i = 1; i < this.pointList.length - 1; i++) {
  254. let dis = SMathUtil.pointToLine(
  255. p,
  256. new SLine(this.pointList[i], this.pointList[i + 1])
  257. );
  258. if (dis.MinDis < len.MinDis) {
  259. len = dis;
  260. index = i;
  261. }
  262. }
  263. }
  264. if (len.MinDis < this.sceneDis) {
  265. if (len.Point) {
  266. this.addPoint(len.Point, index + 1);
  267. }
  268. }
  269. } // Function findAddPos()
  270. /**
  271. * 判断点是否在区域内
  272. *
  273. * @param x
  274. * @param y
  275. * @return true-是
  276. */
  277. contains(x: number, y: number): boolean {
  278. let p = new SPoint(x, y);
  279. for (let i = 1; i < this.pointList.length; i++) {
  280. let PTL = SMathUtil.pointToLine(
  281. p,
  282. new SLine(
  283. this.pointList[i - 1].x,
  284. this.pointList[i - 1].y,
  285. this.pointList[i].x,
  286. this.pointList[i].y
  287. )
  288. );
  289. if (PTL.MinDis < this.sceneDis) {
  290. return true;
  291. }
  292. }
  293. return false;
  294. } // Function contains()
  295. /**
  296. * Item绘制操作
  297. *
  298. * @param painter painter对象
  299. */
  300. onDraw(painter: SPainter): void {
  301. // 缓存场景长度
  302. this.sceneDis = painter.toPx(this.dis);
  303. // 绘制基本图形
  304. painter.pen.lineWidth = painter.toPx(this.lineWidth);
  305. painter.pen.color = new SColor(this.strokeColor);
  306. painter.drawPolyline(this.pointList);
  307. // 创建状态
  308. if (this.status == SItemStatus.Create && this.lastPoint) {
  309. painter.drawLine(
  310. this.pointList[this.pointList.length - 1],
  311. this.lastPoint
  312. );
  313. } else if (this.status == SItemStatus.Edit) {
  314. // 编辑状态
  315. this.pointList.forEach((t, i): void => {
  316. painter.brush.color = SColor.White;
  317. if (i == this.curIndex) {
  318. painter.brush.color = new SColor(this.fillColor);
  319. }
  320. painter.drawCircle(t.x, t.y, painter.toPx(5));
  321. });
  322. }
  323. } // Function onDraw()
  324. } // Class SPolylineItem