SBasePolygonEdit.ts 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. /*
  2. * *********************************************************************************************************************
  3. *
  4. * !!
  5. * .F88X
  6. * X8888Y
  7. * .}888888N;
  8. * i888888N; .:! .I$WI:
  9. * R888888I .'N88~ i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8&
  10. * .R888888I .;N8888~ .X8' "8I.!,/8" !%NY8`"8I8~~8>,88I
  11. * +888888N; .8888888Y "&&8Y.}8,
  12. * ./888888N; .R888888Y .'}~ .>}'.`+> i}! "i' +/' .'i~ !11,.:">, .~]! .i}i
  13. * ~888888%: .I888888l .]88~`1/iY88Ii+1'.R$8$8]"888888888> Y8$ W8E X8E W8888'188Il}Y88$*
  14. * 18888888 E8888881 .]W%8$`R8X'&8%++N8i,8N%N8+l8%` .}8N:.R$RE%N88N%N$K$R 188,FE$8%~Y88I
  15. * .E888888I .i8888888' .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~
  16. * 8888888I .,N888888~ ~88i"8W,!N8*.I88.}888%F,i$88"F88" 888:E8X.>88!i88>`888*.}Fl1]*}1YKi'
  17. * i888888N' I888Y ]88;/EX*IFKFK88X K8R .l8W 88Y ~88}'88E&%8W.X8N``]88!.$8K .:W8I
  18. * .i888888N; I8Y .&8$ .X88! i881.:%888>I88 ;88] +88+.';;;;:.Y88X 18N.,88l .+88/
  19. * .:R888888I
  20. * .&888888I Copyright (c) 2009-2020. 博锐尚格科技股份有限公司
  21. * ~8888'
  22. * .!88~ All rights reserved.
  23. *
  24. * *********************************************************************************************************************
  25. */
  26. import {
  27. SGraphItem,
  28. SGraphPointListDelete,
  29. SGraphPointListInsert,
  30. SGraphPointListUpdate,
  31. SLineStyle
  32. } from "@persagy-web/graph";
  33. import { SKeyCode, SMouseEvent, SUndoStack } from "@persagy-web/base/";
  34. import {
  35. SColor,
  36. SLine,
  37. SLineCapStyle,
  38. SPainter,
  39. SPoint,
  40. SPolygonUtil,
  41. SRect
  42. } from "@persagy-web/draw";
  43. import { SItemStatus, ItemOrder } from "@persagy-web/big";
  44. import { Marker } from "../type/Marker";
  45. import { SMathUtil } from "@persagy-web/big/lib/utils/SMathUtil";
  46. import { SGraphEdit } from ".."
  47. /**
  48. * 编辑多边形
  49. *
  50. * @author 韩耀龙 <han_yao_long@163.com>
  51. */
  52. export class SBasePolygonEdit extends SGraphEdit {
  53. /** X 坐标最小值 */
  54. private minX = Number.MAX_SAFE_INTEGER;
  55. /** X 坐标最大值 */
  56. private maxX = Number.MIN_SAFE_INTEGER;
  57. /** Y 坐标最小值 */
  58. private minY = Number.MAX_SAFE_INTEGER;
  59. /** Y 坐标最大值 */
  60. private maxY = Number.MIN_SAFE_INTEGER;
  61. /** 图例节点对象数据 */
  62. data: Marker;
  63. /** 轮廓线坐标 */
  64. private pointList: SPoint[] = [];
  65. get getPointList(): SPoint[] {
  66. return this.pointList;
  67. } // Get getPointList
  68. set setPointList(arr: SPoint[]) {
  69. this.pointList = arr;
  70. this.update();
  71. } // Set getPointList
  72. /** 当前状态 */
  73. protected _status: number = SItemStatus.Normal;
  74. get status(): SItemStatus {
  75. return this._status;
  76. } // Get status
  77. set status(value: SItemStatus) {
  78. this._status = value;
  79. this.undoStack.clear();
  80. this.update();
  81. } // Set status
  82. /** 边框颜色 */
  83. _strokeColor: SColor = SColor.Black;
  84. /** 画笔颜色 */
  85. get strokeColor(): SColor {
  86. return this._strokeColor;
  87. } // Get strokeColor
  88. set strokeColor(v: SColor) {
  89. this._strokeColor = v;
  90. this.update();
  91. } // Set strokeColor
  92. /** 填充颜色 */
  93. _fillColor: SColor = new SColor("#2196f3");
  94. get fillColor(): SColor {
  95. return this._fillColor;
  96. } // Get fillColor
  97. set fillColor(v: SColor) {
  98. this._fillColor = v;
  99. this.update();
  100. } // Set fillColor
  101. /** 边框样式 */
  102. _lineStyle: SLineStyle = SLineStyle.Solid;
  103. get lineStyle(): SLineStyle {
  104. return this._lineStyle;
  105. } // Get lineStyle
  106. set lineStyle(v: SLineStyle) {
  107. this._lineStyle = v;
  108. this.update();
  109. } // Set lineStyle
  110. /** 边框的宽只可输入像素宽 */
  111. _lineWidth: number = 1;
  112. get lineWidth(): number {
  113. return this._lineWidth;
  114. } // Get lineWidth
  115. set lineWidth(v: number) {
  116. this._lineWidth = v;
  117. this.update();
  118. } // Set lineWidth
  119. /** 是否闭合 */
  120. closeFlag: boolean = false;
  121. /** 鼠标移动点 */
  122. private lastPoint: SPoint | null = null;
  123. /** 当前鼠标获取顶点对应索引 */
  124. private curIndex: number = -1;
  125. /** 当前鼠标获取顶点对应坐标 */
  126. private curPoint: null | SPoint = null;
  127. /** 灵敏像素 */
  128. private len: number = 10;
  129. /** 场景像素内部将灵敏像素换算为场景实际距离 */
  130. private scenceLen: number = 15;
  131. /** 场景像素 */
  132. private isAlt: boolean = false;
  133. /** undo/redo 堆栈 */
  134. protected undoStack: SUndoStack = new SUndoStack();
  135. /**
  136. * 构造函数
  137. *
  138. * @param parent 指向父对象
  139. * @param data 图例节点对象数据
  140. */
  141. constructor(parent: SGraphItem | null, data: Marker) {
  142. super(parent);
  143. // this.textItem.originPosition = STextOrigin.Centrum;
  144. // this.textItem.isTransform = false;
  145. this.zOrder = ItemOrder.polygonOrder;
  146. this.data = data;
  147. this.name = data.name;
  148. // this.text = data.Name;
  149. if (data.style) {
  150. this.setPointList = [];
  151. let setPointList: SPoint[];
  152. if (data.style.outLine) {
  153. if (data.style.outLine[0] instanceof SPoint) {
  154. // @ts-ignore
  155. this.setPointList = data.style.outLine;
  156. } else {
  157. setPointList = data.style.outLine.map(i => {
  158. return (new SPoint(i.x, i.y))
  159. })
  160. this.setPointList = setPointList;
  161. }
  162. }
  163. // 样式相关
  164. if (data.style.default) {
  165. // 颜色
  166. if (data.style.default.strokeColor) {
  167. this.strokeColor = new SColor(data.style.default.strokeColor)
  168. }
  169. // 线宽
  170. if (data.style.default.lineWidth) {
  171. this.lineWidth = data.style.default.lineWidth
  172. }
  173. // 线样式
  174. if (data.style.default.lineStyle) {
  175. this.lineStyle = data.style.default.lineStyle
  176. }
  177. // 填充色
  178. if (data.style.default.fillColor) {
  179. this.fillColor = new SColor(data.style.default.fillColor)
  180. }
  181. }
  182. }
  183. // if (data) {
  184. // if (data.Properties.Zorder) {
  185. // this.zOrder = data.Properties.Zorder;
  186. // }
  187. // // 设置线宽
  188. // if (data.Properties.TextPos) {
  189. // this.textItem.moveTo(data.Properties.TextPos.X, data.Properties.TextPos.Y);
  190. // }
  191. // if (data.Properties.color) {
  192. // this.color = new SColor(data.Properties.color);
  193. // }
  194. // if (data.Properties.font) {
  195. // this.font = new SFont("sans-serif", data.Properties.font);
  196. // }
  197. // if (data.Properties && data.Properties.IsActive) {
  198. // this.isActive = data.Properties.IsActive;
  199. // }
  200. // }
  201. // 监听多边形创建完成事件,并动态计算文本位置
  202. // this.connect("finishCreated", this, () => {
  203. // // 计算文本位置
  204. // let x: number = this.getPointList.reduce((pre, cur, index, arr) => {
  205. // return pre + (cur.x / arr.length)
  206. // }, 0),
  207. // y: number = this.getPointList.reduce((pre, cur, index, arr) => {
  208. // return pre + (cur.y / arr.length)
  209. // }, 0);
  210. // this.textItem.moveTo(x, y);
  211. // })
  212. }
  213. //////////////////
  214. // 以下为对pointList 数组的操作方法
  215. /**
  216. * 储存新的多边形顶点
  217. *
  218. * @param x 点位得 x 坐标
  219. * @param y 点位得 y 坐标
  220. * @param i 储存所在索引
  221. * @return 添加的顶点
  222. */
  223. insertPoint(x: number, y: number, i: number | null = null): SPoint {
  224. const point = new SPoint(x, y);
  225. if (i == null) {
  226. this.pointList.push(point);
  227. } else {
  228. this.pointList.splice(i, 0, point);
  229. }
  230. this.update();
  231. return point;
  232. } // Function insertPoint()
  233. /**
  234. * 删除点位
  235. *
  236. * @param i 删除点所在的索引
  237. * @return 索引不在数组范围则返回 null
  238. */
  239. deletePoint(i: number | null = null): SPoint | null {
  240. let point = null;
  241. if (i != null) {
  242. if (i >= this.pointList.length || i < 0) {
  243. point = null;
  244. } else {
  245. point = new SPoint(this.pointList[i].x, this.pointList[i].y);
  246. this.pointList.splice(i, 1);
  247. }
  248. } else {
  249. if (this.pointList.length) {
  250. point = this.pointList[this.pointList.length - 1];
  251. this.pointList.pop();
  252. } else {
  253. point = null;
  254. }
  255. }
  256. this.curIndex = -1;
  257. this.curPoint = null;
  258. this.update();
  259. return point;
  260. } // Function deletePoint()
  261. /**
  262. * 多边形顶点的移动位置
  263. *
  264. * @param x 点位得 x 坐标
  265. * @param y 点位得 y 坐标
  266. * @param i 点位得 i 坐标
  267. * @return 移动对应得点。如果索引无法找到移动顶点,则返回 null
  268. */
  269. movePoint(x: number, y: number, i: number): SPoint | null {
  270. let point = null;
  271. if (i >= this.pointList.length || i < 0) {
  272. return null;
  273. }
  274. if (this.pointList.length) {
  275. this.pointList[i].x = x;
  276. this.pointList[i].y = y;
  277. }
  278. point = this.pointList[i];
  279. return point;
  280. } // Function movePoint()
  281. /**
  282. * 展示状态 -- 绘制多边形数组
  283. *
  284. * @param painter 绘制类
  285. * @param pointList 绘制多边形数组
  286. */
  287. protected drawShowPolygon(painter: SPainter, pointList: SPoint[]): void {
  288. painter.save();
  289. painter.pen.lineCapStyle = SLineCapStyle.Square;
  290. painter.pen.color = this.strokeColor;
  291. painter.brush.color = this.fillColor;
  292. painter.pen.lineWidth = painter.toPx(this.lineWidth);
  293. if (this.lineStyle == SLineStyle.Dashed) {
  294. painter.pen.lineDash = [
  295. painter.toPx(this.lineWidth * 3),
  296. painter.toPx(this.lineWidth * 7)
  297. ];
  298. } else if (this.lineStyle == SLineStyle.Dotted) {
  299. painter.pen.lineDash = [
  300. painter.toPx(this.lineWidth),
  301. painter.toPx(this.lineWidth)
  302. ];
  303. }
  304. if (this.selected) {
  305. painter.shadow.shadowBlur = 10;
  306. painter.shadow.shadowColor = new SColor(`#00000033`);
  307. painter.shadow.shadowOffsetX = 5;
  308. painter.shadow.shadowOffsetY = 5;
  309. } else {
  310. painter.shadow.shadowColor = SColor.Transparent;
  311. }
  312. painter.drawPolygon([...pointList]);
  313. painter.restore();
  314. } // Function drawShowPolygon()
  315. /**
  316. * 创建状态 -- 绘制多边形数组
  317. *
  318. * @param painter 绘制类
  319. * @param pointList 绘制多边形数组
  320. */
  321. protected drawCreatePolygon(painter: SPainter, pointList: SPoint[]): void {
  322. painter.pen.lineCapStyle = SLineCapStyle.Square;
  323. painter.pen.color = this.strokeColor;
  324. painter.pen.lineWidth = painter.toPx(this.lineWidth);
  325. if (this.lastPoint && pointList.length) {
  326. painter.drawLine(
  327. pointList[pointList.length - 1].x,
  328. pointList[pointList.length - 1].y,
  329. this.lastPoint.x,
  330. this.lastPoint.y
  331. );
  332. }
  333. painter.drawPolyline(pointList);
  334. painter.pen.color = SColor.Transparent;
  335. painter.brush.color = new SColor(this.fillColor.value);
  336. painter.pen.lineWidth = painter.toPx(this.lineWidth);
  337. if (this.lastPoint) {
  338. painter.drawPolygon([...pointList, this.lastPoint]);
  339. // 绘制顶点块
  340. painter.pen.color = SColor.Black;
  341. painter.brush.color = SColor.White;
  342. pointList.forEach(item => {
  343. painter.drawCircle(item.x, item.y, painter.toPx(this.len / 2));
  344. });
  345. // 如果最后一个点在第一个点的灵敏度范围内,第一个点填充变红
  346. if (this.pointList.length) {
  347. if (
  348. SMathUtil.pointDistance(
  349. this.lastPoint.x,
  350. this.lastPoint.y,
  351. this.pointList[0].x,
  352. this.pointList[0].y
  353. ) < this.scenceLen
  354. ) {
  355. // 绘制第一个点的顶点块
  356. painter.pen.color = SColor.Black;
  357. painter.brush.color = SColor.Red;
  358. painter.drawCircle(
  359. this.pointList[0].x,
  360. this.pointList[0].y,
  361. painter.toPx(this.len / 2)
  362. );
  363. }
  364. }
  365. } else {
  366. painter.drawPolygon(pointList);
  367. }
  368. } // Function drawCreatePolygon()
  369. /**
  370. *
  371. * 编辑状态 -- 绘制多边形数组
  372. *
  373. * @param painter 绘制类
  374. * @param pointList 绘制多边形数组
  375. */
  376. protected drawEditPolygon(painter: SPainter, pointList: SPoint[]): void {
  377. // 展示多边形
  378. painter.pen.lineCapStyle = SLineCapStyle.Square;
  379. painter.pen.color = this.strokeColor;
  380. painter.pen.lineWidth = painter.toPx(this.lineWidth);
  381. painter.brush.color = new SColor(this.fillColor.value);
  382. painter.drawPolygon([...pointList]);
  383. // 绘制顶点块
  384. painter.pen.color = SColor.Black;
  385. painter.brush.color = SColor.White;
  386. pointList.forEach((item, index) => {
  387. painter.brush.color = SColor.White;
  388. if (index == this.curIndex) {
  389. painter.brush.color = new SColor("#2196f3");
  390. }
  391. painter.drawCircle(item.x, item.y, painter.toPx(this.len / 2));
  392. });
  393. } // Function drawCreatePolygon()
  394. /**
  395. * 编辑状态操作多边形数组
  396. *
  397. * @param event 鼠标事件
  398. */
  399. protected editPolygonPoint(event: SMouseEvent): void {
  400. // 判断是否为删除状态 isAlt = true为删除状态
  401. if (this.isAlt) {
  402. // 1 判断是否点击在多边形顶点
  403. let lenIndex = -1; // 当前点击到的点位索引;
  404. let curenLen = this.scenceLen; // 当前的灵敏度
  405. this.pointList.forEach((item, index) => {
  406. let dis = SMathUtil.pointDistance(
  407. event.x,
  408. event.y,
  409. item.x,
  410. item.y
  411. );
  412. if (dis < curenLen) {
  413. curenLen = dis;
  414. lenIndex = index;
  415. }
  416. });
  417. // 若点击到,对该索引对应的点做删除
  418. if (lenIndex != -1) {
  419. if (this.pointList.length <= 3) {
  420. return;
  421. }
  422. const delePoint = new SPoint(
  423. this.pointList[lenIndex].x,
  424. this.pointList[lenIndex].y
  425. );
  426. this.deletePoint(lenIndex);
  427. // 记录顶点操作记录压入堆栈
  428. this.recordAction(SGraphPointListDelete, [
  429. this.pointList,
  430. delePoint,
  431. lenIndex
  432. ]);
  433. }
  434. } else {
  435. // 1 判断是否点击在多边形顶点
  436. this.curIndex = -1;
  437. this.curPoint = null;
  438. let lenIndex = -1; // 当前点击到的点位索引;
  439. let curenLen = this.scenceLen; // 当前的灵敏度
  440. this.pointList.forEach((item, index) => {
  441. let dis = SMathUtil.pointDistance(
  442. event.x,
  443. event.y,
  444. item.x,
  445. item.y
  446. );
  447. if (dis < curenLen) {
  448. curenLen = dis;
  449. lenIndex = index;
  450. }
  451. });
  452. this.curIndex = lenIndex;
  453. // 2判断是否点击在多边形得边上
  454. if (-1 == lenIndex) {
  455. let len = SMathUtil.pointToLine(
  456. new SPoint(event.x, event.y),
  457. new SLine(this.pointList[0], this.pointList[1])
  458. ),
  459. index = 0;
  460. if (this.pointList.length > 2) {
  461. for (let i = 1; i < this.pointList.length; i++) {
  462. let dis = SMathUtil.pointToLine(
  463. new SPoint(event.x, event.y),
  464. new SLine(this.pointList[i], this.pointList[i + 1])
  465. );
  466. if (i + 1 == this.pointList.length) {
  467. dis = SMathUtil.pointToLine(
  468. new SPoint(event.x, event.y),
  469. new SLine(this.pointList[i], this.pointList[0])
  470. );
  471. }
  472. if (dis.MinDis < len.MinDis) {
  473. len = dis;
  474. index = i;
  475. }
  476. }
  477. }
  478. // 判断是否有点
  479. if (len.Point) {
  480. // 点在了多边形的边上
  481. if (len.MinDis <= this.scenceLen) {
  482. this.pointList.splice(index + 1, 0, len.Point);
  483. // 记录新增顶点操作记录压入堆栈
  484. this.recordAction(SGraphPointListInsert, [
  485. this.pointList,
  486. len.Point,
  487. index + 1
  488. ]);
  489. } else {
  490. //没点在多边形边上也没点在多边形顶点上
  491. super.onMouseDown(event);
  492. }
  493. }
  494. } else {
  495. // 当捕捉到顶点后 ,记录当前点的xy坐标,用于undo、redo操作
  496. this.curPoint = new SPoint(
  497. this.pointList[this.curIndex].x,
  498. this.pointList[this.curIndex].y
  499. );
  500. }
  501. // 刷新视图
  502. this.update();
  503. }
  504. } // Function editPolygonPoint()
  505. /////////////////////
  506. // undo、redo相关操作
  507. /**
  508. * 记录相关动作并推入栈中
  509. *
  510. * @param SGraphCommand 相关命令类
  511. * @param any 对应传入参数
  512. */
  513. protected recordAction(SGraphCommand: any, any: any[]): void {
  514. // 记录相关命令并推入堆栈中
  515. const sgraphcommand = new SGraphCommand(this.scene, this, ...any);
  516. this.undoStack.push(sgraphcommand);
  517. } // Function recordAction()
  518. /**
  519. * 执行取消操作执行
  520. */
  521. undo(): void {
  522. if (this.status == SItemStatus.Normal) {
  523. return;
  524. }
  525. this.undoStack.undo();
  526. } // Function undo()
  527. /**
  528. * 执行重做操作执行
  529. */
  530. redo(): void {
  531. if (this.status == SItemStatus.Normal) {
  532. return;
  533. }
  534. this.undoStack.redo();
  535. } // Function redo()
  536. ///////////////////////////////
  537. // 以下为鼠标事件
  538. /**
  539. * 鼠标双击事件
  540. *
  541. * @param event 事件参数
  542. * @return 是否处理该事件
  543. */
  544. onDoubleClick(event: SMouseEvent): boolean {
  545. // 如果位show状态 双击改对象则需改为编辑状态
  546. if (SItemStatus.Normal == this.status) {
  547. this.status = SItemStatus.Edit;
  548. this.grabItem(this);
  549. } else if (SItemStatus.Edit == this.status) {
  550. this.status = SItemStatus.Normal;
  551. this.releaseItem();
  552. }
  553. this.update();
  554. return true;
  555. } // Function onDoubleClick()
  556. /**
  557. * 键盘事件
  558. *
  559. * @param event 事件参数
  560. * @return 是否处理该事件
  561. */
  562. onKeyDown(event: KeyboardEvent): boolean {
  563. if (this.status == SItemStatus.Normal) {
  564. return false;
  565. } else if (this.status == SItemStatus.Create) {
  566. if (event.code == "Enter") {
  567. // 当顶点大于二个时才又条件执行闭合操作并清空堆栈
  568. if (this.pointList.length > 2) {
  569. this.status = SItemStatus.Normal;
  570. //3 传递完成事件状态
  571. this.$emit("finishCreated");
  572. //1 grabItem 置为null
  573. this.releaseItem();
  574. }
  575. }
  576. } else if (this.status == SItemStatus.Edit) {
  577. if (event.key == "Alt") {
  578. this.isAlt = true;
  579. }
  580. }
  581. this.update();
  582. return true;
  583. } // Function onKeyDown()
  584. /**
  585. * 键盘键抬起事件
  586. *
  587. * @param event 事件参数
  588. */
  589. onKeyUp(event: KeyboardEvent): void {
  590. if (this.status == SItemStatus.Edit) {
  591. if (event.key == "Alt") {
  592. this.isAlt = false;
  593. } else if (event.keyCode == SKeyCode.Delete) {
  594. // 当多边形的顶点大于三个允许删除点
  595. if (this.pointList.length > 3) {
  596. this.deletePoint(this.curIndex);
  597. }
  598. }
  599. }
  600. this.update();
  601. } // Function onKeyUp()
  602. /**
  603. * 鼠标按下事件
  604. *
  605. * @param event 事件参数
  606. * @return 是否处理该事件
  607. */
  608. onMouseDown(event: SMouseEvent): boolean {
  609. if (event.shiftKey) {
  610. event = this.compare(event);
  611. }
  612. // 如果状态为编辑状态则添加点
  613. if (this.status == SItemStatus.Create) {
  614. // 新增顶点
  615. let len = -1;
  616. if (this.pointList.length) {
  617. len = SMathUtil.pointDistance(
  618. event.x,
  619. event.y,
  620. this.pointList[0].x,
  621. this.pointList[0].y
  622. );
  623. }
  624. if (this.pointList.length > 2 && len > 0 && len < this.scenceLen) {
  625. this.status = SItemStatus.Normal;
  626. //3 传递完成事件状态
  627. this.$emit("finishCreated");
  628. //1 grabItem 置为null
  629. this.releaseItem();
  630. } else {
  631. this.insertPoint(event.x, event.y);
  632. // 记录新增顶点操作记录压入堆栈
  633. let pos = new SPoint(event.x, event.y);
  634. this.recordAction(SGraphPointListInsert, [this.pointList, pos]);
  635. }
  636. } else if (this.status == SItemStatus.Edit) {
  637. // 对多边形数组做编辑操作
  638. this.editPolygonPoint(event);
  639. } else {
  640. return super.onMouseDown(event);
  641. }
  642. return true;
  643. } // Function onMouseDown()
  644. /**
  645. * 鼠标移入事件
  646. *
  647. * @param event 事件参数
  648. * @return 是否处理该事件
  649. */
  650. onMouseEnter(event: SMouseEvent): boolean {
  651. return true;
  652. } // Function onMouseEnter()
  653. /**
  654. * 鼠标移出事件
  655. *
  656. * @param event 事件参数
  657. * @return 是否处理该事件
  658. */
  659. onMouseLeave(event: SMouseEvent): boolean {
  660. return true;
  661. } // Function onMouseLeave()
  662. /**
  663. * 鼠标移动事件
  664. *
  665. * @param event 事件参数
  666. * @return 是否处理该事件
  667. */
  668. onMouseMove(event: SMouseEvent): boolean {
  669. if (event.shiftKey) {
  670. event = this.compare(event);
  671. }
  672. if (this.status == SItemStatus.Create) {
  673. this.lastPoint = new SPoint();
  674. this.lastPoint.x = event.x;
  675. this.lastPoint.y = event.y;
  676. this.update();
  677. } else if (this.status == SItemStatus.Edit) {
  678. if (event.buttons == 1) {
  679. if (-1 != this.curIndex) {
  680. this.pointList[this.curIndex].x = event.x;
  681. this.pointList[this.curIndex].y = event.y;
  682. }
  683. }
  684. this.update();
  685. } else {
  686. return super.onMouseMove(event);
  687. }
  688. return true;
  689. } // Function onMouseMove()
  690. /**
  691. * shift 垂直水平创建或编辑
  692. *
  693. * @param event 事件
  694. */
  695. compare(event: SMouseEvent): SMouseEvent {
  696. if (this.pointList.length) {
  697. let last = new SPoint(event.x, event.y);
  698. if (this.status == SItemStatus.Create) {
  699. last = this.pointList[this.pointList.length - 1];
  700. } else if (this.status == SItemStatus.Edit) {
  701. if (this.curIndex > 0) {
  702. last = this.pointList[this.curIndex - 1];
  703. }
  704. }
  705. const dx = Math.abs(event.x - last.x);
  706. const dy = Math.abs(event.y - last.y);
  707. if (dy > dx) {
  708. event.x = last.x;
  709. } else {
  710. event.y = last.y;
  711. }
  712. }
  713. return event;
  714. } // Function compare()
  715. /**
  716. * 鼠标抬起事件
  717. *
  718. * @param event 事件参数
  719. * @return 是否处理该事件
  720. */
  721. onMouseUp(event: SMouseEvent): boolean {
  722. if (this.status == SItemStatus.Edit) {
  723. if (-1 != this.curIndex) {
  724. const pos = new SPoint(
  725. this.pointList[this.curIndex].x,
  726. this.pointList[this.curIndex].y
  727. );
  728. this.recordAction(SGraphPointListUpdate, [
  729. this.pointList,
  730. this.curPoint,
  731. pos,
  732. this.curIndex
  733. ]);
  734. }
  735. } else if (this.status == SItemStatus.Normal) {
  736. this.moveToOrigin(this.x, this.y);
  737. return super.onMouseUp(event);
  738. }
  739. return true;
  740. } // Function onMouseUp()
  741. /**
  742. * 移动后处理所有坐标,并肩原点置为场景原点
  743. *
  744. * @param x x 坐标
  745. * @param y y 坐标
  746. */
  747. moveToOrigin(x: number, y: number): void {
  748. super.moveToOrigin(x, y);
  749. this.pointList = this.pointList.map(t => {
  750. t.x = t.x + x;
  751. t.y = t.y + y;
  752. return t;
  753. });
  754. this.x = 0;
  755. this.y = 0;
  756. } // Function moveToOrigin()
  757. /**
  758. * 适配事件
  759. *
  760. * @param event 事件参数
  761. * @return 是否处理该事件
  762. */
  763. onResize(event: SMouseEvent): boolean {
  764. return true;
  765. } // Function onResize()
  766. /**
  767. * 取消操作
  768. */
  769. cancelOperate(): void {
  770. // 当状态为展示状态
  771. if (this.status == SItemStatus.Create) {
  772. // 闭合多边形
  773. this.parent = null;
  774. } else if (this.status == SItemStatus.Edit) {
  775. // 编辑状态
  776. this.status = SItemStatus.Normal;
  777. }
  778. this.update();
  779. } // Function cancelOperate()
  780. /**
  781. * Item 对象边界区域
  782. *
  783. * @return 边界区域
  784. */
  785. boundingRect(): SRect {
  786. if (this.pointList.length) {
  787. this.minX = this.pointList[0].x;
  788. this.maxX = this.pointList[0].x;
  789. this.minY = this.pointList[0].y;
  790. this.maxY = this.pointList[0].y;
  791. this.pointList.forEach(it => {
  792. let x = it.x,
  793. y = it.y;
  794. if (x < this.minX) {
  795. this.minX = x;
  796. }
  797. if (y < this.minY) {
  798. this.minY = y;
  799. }
  800. if (x > this.maxX) {
  801. this.maxX = x;
  802. }
  803. if (y > this.maxY) {
  804. this.maxY = y;
  805. }
  806. });
  807. }
  808. return new SRect(
  809. this.minX,
  810. this.minY,
  811. this.maxX - this.minX,
  812. this.maxY - this.minY
  813. );
  814. } // Function boundingRect()
  815. /**
  816. * 判断点是否在区域内
  817. *
  818. * @param x x 坐标
  819. * @param y y 坐标
  820. * @return 是否在该区域内
  821. */
  822. contains(x: number, y: number): boolean {
  823. let arr = this.pointList;
  824. if (arr.length < 3 || !SPolygonUtil.pointIn(x, y, arr)) {
  825. return false;
  826. }
  827. return true;
  828. } // Function contains()
  829. /**
  830. * 返回对象储存的相关数据
  831. *
  832. * @return 对象参数
  833. */
  834. toData() : any {
  835. const Line = this.pointList.map(pos => {
  836. return {
  837. x: pos.x,
  838. y: pos.y
  839. }
  840. });
  841. this.data.style.outLine = Line;
  842. this.data.style.default.lineWidth = this.lineWidth;
  843. this.data.style.default.lineStyle = this.lineStyle;
  844. this.data.style.default.strokeColor = this.strokeColor.value;
  845. this.data.style.default.fillColor = this.fillColor.value;
  846. return this.data
  847. } // Function toData()
  848. /**
  849. * Item 绘制操作
  850. *
  851. * @param painter 绘制对象
  852. */
  853. onDraw(painter: SPainter): void {
  854. this.scenceLen = painter.toPx(this.len);
  855. // 当状态为展示状态
  856. if (this.status == SItemStatus.Normal) {
  857. // 闭合多边形
  858. this.drawShowPolygon(painter, this.pointList);
  859. } else if (this.status == SItemStatus.Create) {
  860. // 创建状态
  861. this.drawCreatePolygon(painter, this.pointList);
  862. } else {
  863. // 编辑状态
  864. this.drawEditPolygon(painter, this.pointList);
  865. }
  866. } // Function onDraw()
  867. } // Class SBasePolygonEdit