SBaseEditScene.ts 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  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) 2016-2020. 博锐尚格科技股份有限公司
  21. * ~8888'
  22. * .!88~ All rights reserved.
  23. *
  24. * *********************************************************************************************************************
  25. */
  26. import {
  27. SGraphDeleteListCommand,
  28. SGraphEditScene,
  29. SGraphEdit
  30. } from "@persagy-web/edit";
  31. import { SMouseEvent } from "@persagy-web/base/lib";
  32. import { SArrowStyleType, SPoint, SRect } from "@persagy-web/draw";
  33. import { SItemStatus, SRectSelectItem } from "@persagy-web/big/lib";
  34. import {
  35. SGraphItem,
  36. SGraphSelectContainer,
  37. SOrderSetType
  38. } from "@persagy-web/graph/lib/";
  39. import { SBaseArrow, SBaseExplainEdit, SBasePipe } from "./";
  40. import { SBaseArrowPolyEdit } from "./items/SBaseArrowPolyEdit";
  41. import { SGraphAddListCommand } from "@persagy-web/edit/lib/commands/SGraphAddListCommand";
  42. /**
  43. * big-edit 场景
  44. *
  45. * @author 韩耀龙 <han_yao_long@163.com>
  46. */
  47. export class SBaseEditScene extends SGraphEditScene {
  48. /** 图例节点 */
  49. Nodes: any = []; // 图例节点,所有与工程信息化相关的图例(图标类型与区域) // 与工程信息无关的标识对象(增加文本注释,图上的图片说明)
  50. /** 图例节点 */ Markers: any = [];
  51. /** 管线对象 */
  52. Relations: any = [];
  53. /** 复制的对象 */
  54. copyString: any[] = [];
  55. /** 选中的对象 */
  56. grabItem: null | SGraphEdit | SGraphItem = null;
  57. /**
  58. * 构造函数
  59. *
  60. */
  61. constructor() {
  62. super();
  63. }
  64. /**
  65. * 新增基础类注释
  66. *
  67. * @param event 鼠标事件参数
  68. * @return 新增的基础类注释
  69. */
  70. addExplainItem(event: SMouseEvent): SBaseExplainEdit {
  71. const data = {
  72. /** 名称 */
  73. name: "基础注释文本",
  74. /** 图标 */
  75. type: "Text",
  76. /** 位置 */
  77. pos: { x: event.x, y: event.y },
  78. /** 由应用自己定义 */
  79. properties: {
  80. type: "BaseExplain"
  81. },
  82. style: {
  83. default: {
  84. text: "请在右侧属性栏输入文字!",
  85. color: "#646c73",
  86. font: 14,
  87. backgroundcolor: "#f7f9facc"
  88. }
  89. }
  90. };
  91. const item = new SBaseExplainEdit(null, data);
  92. item.moveTo(event.x, event.y);
  93. item.selectable = true;
  94. item.moveable = true;
  95. this.addItem(item);
  96. this.grabItem = null;
  97. item.connect("onContextMenu", this, this.getItem);
  98. this.finishCreated(item);
  99. return item;
  100. }
  101. /**
  102. * 新增基础箭头(折线)
  103. *
  104. * @param event 鼠标事件
  105. * @return 新增的基础箭头(折线)
  106. */
  107. addPolyLineArrow(event: SMouseEvent): SBaseArrow {
  108. const data = {
  109. name: "基础箭头",
  110. type: "Arrow",
  111. pos: { x: 0, y: 0 },
  112. properties: {
  113. type: "BaseArrow"
  114. },
  115. style: {
  116. outLine: [{ x: event.x, y: event.y }],
  117. begin: SArrowStyleType.None, //开端箭头样式
  118. end: SArrowStyleType.None, //结尾箭头样式
  119. isMove: true, //是否可以移动
  120. default: {}
  121. }
  122. };
  123. const item = new SBaseArrow(null, data);
  124. item.status = SItemStatus.Create;
  125. item.selectable = true;
  126. this.addItem(item);
  127. this.grabItem = item;
  128. item.connect("finishCreated", this, this.finishCreated);
  129. item.connect("onContextMenu", this, this.getItem);
  130. // view 必须存在
  131. if (this.view) {
  132. this.view.update();
  133. }
  134. return item;
  135. }
  136. /**
  137. * 新增基础箭头(多边形)
  138. *
  139. * @param event 鼠标事件
  140. * @return 新增的基础箭头(多边形)
  141. */
  142. addPolygonArrow(event: SMouseEvent): SBaseArrowPolyEdit {
  143. const data = {
  144. /** 名称 */
  145. name: "多边形箭头",
  146. /** 图标(Image),线类型(Line) */
  147. type: "ArrowPolygon",
  148. /** 缩放比例(Image),线类型(Line) */
  149. scale: { x: 1, y: 1, z: 1 },
  150. /** 缩放比例(Image),线类型(Line) */
  151. rolate: { x: 0, y: 0, z: 0 },
  152. /** 位置 */
  153. pos: { x: 0, y: 0 },
  154. /** 由应用自己定义 */
  155. properties: {
  156. type: "BaseArrowPolygon" // 自定义类型用于区分mark与node
  157. },
  158. style: {
  159. line: [{ x: event.x, y: event.y }],
  160. default: {}
  161. }
  162. };
  163. const item = new SBaseArrowPolyEdit(null, data);
  164. item.status = SItemStatus.Create;
  165. item.selectable = true;
  166. this.addItem(item);
  167. this.grabItem = item;
  168. item.connect("finishCreated", this, this.finishCreated);
  169. item.connect("onContextMenu", this, this.getItem);
  170. // view 必须存在
  171. if (this.view) {
  172. // 视图存在缩放比例,箭头宽度随缩放比例改变
  173. if (this.view?.scale) {
  174. item.arrowWidth = item.arrowWidth / this.view.scale;
  175. }
  176. this.view.update();
  177. }
  178. return item;
  179. }
  180. // /**
  181. // * 添加基本设备 item
  182. // *
  183. // * @param event 鼠标事件
  184. // * @param legendObj 图例样式
  185. // */
  186. // addEuqipment(event: SMouseEvent, legendObj: any): void {
  187. // const data = {
  188. // nodeId: uuid(),
  189. // /** 名称 */
  190. // name: '基础设备',
  191. // /** 返回物理世界对象 ID 列表 */
  192. // attachObjectIds: [],
  193. // size: { width: 50, height: 50 },
  194. // /** 图标 (Image),线类型 (Line) */
  195. // type: "Image",
  196. // /** 位置 */
  197. // pos: { x: event.x, y: event.y },
  198. // /** 由应用自己定义 */
  199. // properties: {
  200. // type: "BaseEquipment",
  201. // infoMsgList: [{
  202. // }]
  203. // },
  204. // style: {
  205. // default: {
  206. // strokecolor: "#c0ccda",
  207. // url: require('./../../../assets/images/equip/' + legendObj.url),
  208. // }
  209. // }
  210. // }
  211. // const item = new SBaseEquipment(null, data);
  212. // item.status = SItemStatus.Create;
  213. // this.addItem(item);
  214. // item.selectable = true;
  215. // item.moveable = true;
  216. // this.grabItem = item;
  217. // this.finishCreated(item)
  218. // item.connect("onContextMenu", this, this.getItem);
  219. // if (this.view) {
  220. // this.view.update();
  221. // }
  222. // }
  223. /**
  224. * 新增管道
  225. *
  226. * @param event 鼠标事件
  227. * @return 新增的管道
  228. */
  229. addBasePipe(event: SMouseEvent, legendObj: any): SBasePipe {
  230. const anc = this.isAdsorb ? this.clickIsAnchor(event) :null;
  231. // 锚点时否存在
  232. if (anc) {
  233. const p = anc.mapToScene(0, 0);
  234. anc.isConnected = true;
  235. event.x = p.x;
  236. event.y = p.y;
  237. }
  238. const data = {
  239. name: legendObj.name,
  240. graphElementId: legendObj.id,
  241. lineType: "",
  242. node1Id: "",
  243. node2Id: "",
  244. anchor1Id: "",
  245. anchor2Id: "",
  246. pointList: [{ x: event.x, y: event.y }],
  247. properties: {
  248. type: "BasePipe"
  249. },
  250. style: {
  251. default: {
  252. strokeColor: legendObj.color,
  253. lineWidth: 4
  254. }
  255. }
  256. };
  257. const item = new SBasePipe(null, data);
  258. item.status = SItemStatus.Create;
  259. item.selectable = true;
  260. this.addItem(item);
  261. this.grabItem = item;
  262. // 起始锚点
  263. item.startAnchor = anc;
  264. // 锚点事件绑定
  265. if (anc) {
  266. anc.parent?.connect("changePos", item, item.changePos);
  267. item.anchor1Id = anc.id;
  268. item.node1Id = anc.parent ? anc.parent.nodeId : "";
  269. }
  270. item.connect("finishCreated", this, this.finishCreated);
  271. item.connect("onContextMenu", this, this.getItem);
  272. if (this.view) {
  273. this.view.update();
  274. }
  275. return item;
  276. }
  277. /**
  278. * 重做
  279. */
  280. redo(): void {
  281. if (this.grabItem && this.grabItem instanceof SGraphEdit) {
  282. this.grabItem.redo();
  283. } else {
  284. this.undoStack.redo();
  285. }
  286. }
  287. /**
  288. * 撤销
  289. */
  290. undo(): void {
  291. if (this.grabItem && this.grabItem instanceof SGraphEdit) {
  292. this.grabItem.undo();
  293. } else {
  294. this.undoStack.undo();
  295. }
  296. }
  297. /**
  298. * 删除
  299. *
  300. * @return 删除的图例
  301. */
  302. deleteItem(itemArr: SGraphItem[] = []): any {
  303. let itemList: SGraphItem[] = [];
  304. if (itemArr && itemArr.length && itemArr[0]) {
  305. itemList = [...itemArr];
  306. } else {
  307. if (this.selectContainer.count == 0) {
  308. return [];
  309. }
  310. itemList = this.selectContainer.itemList;
  311. this.undoStack.push(
  312. new SGraphDeleteListCommand(this, [...itemList])
  313. );
  314. }
  315. // 推入 undo/redo 栈
  316. itemList.forEach((element: any) => {
  317. this.removeItem(element);
  318. });
  319. // view 必须存在
  320. if (this.view) {
  321. this.view.update();
  322. }
  323. return itemList;
  324. }
  325. /**
  326. * 框选
  327. */
  328. addRectSelect(event: SMouseEvent): void {
  329. let point = new SPoint(event.x, event.y);
  330. let rect = new SRectSelectItem(null, point);
  331. this.addItem(rect);
  332. this.grabItem = rect;
  333. }
  334. /**
  335. * 计算框选交集
  336. *
  337. * @param ctrl 是否点击ctrl
  338. */
  339. groupSelect(ctrl: boolean) {
  340. // 判断当前图例是否为选中框
  341. if (this.grabItem instanceof SRectSelectItem) {
  342. const rect = this.grabItem.boundingRect();
  343. this.arrToSelect(this.root.children, rect);
  344. }
  345. }
  346. /**
  347. * 选中item:框选
  348. *
  349. * @param arr 实例数组
  350. * @param rect 框选矩形区域
  351. */
  352. private arrToSelect(arr: SGraphItem[], rect: SRect) {
  353. // 数组不为空
  354. if (Array.isArray(arr) && arr.length) {
  355. // 对框选范围内的对象高亮显示
  356. arr.forEach(t => {
  357. if (!(t instanceof SGraphSelectContainer) && t.parent) {
  358. if (t.visible) {
  359. let temp = t.boundingRect();
  360. let lefttop = t.mapToScene(temp.left, temp.top);
  361. let rightbottom = t.mapToScene(temp.right, temp.bottom);
  362. let r = new SRect(lefttop, rightbottom);
  363. if (rect.isIn(r)) {
  364. this.selectContainer.toggleItem(t);
  365. }
  366. }
  367. }
  368. });
  369. }
  370. }
  371. /////////////////////////////////////////////////////////////////////
  372. // 鼠标事件
  373. /**
  374. * 鼠标左键按下
  375. *
  376. * @param event 鼠标事件参数
  377. */
  378. onMouseDown(event: SMouseEvent): any {
  379. if (!super.onMouseDown(event) && 1 == event.buttons) {
  380. this.addRectSelect(event);
  381. }
  382. }
  383. /**
  384. * 鼠标抬起
  385. *
  386. * @param event 鼠标事件参数
  387. */
  388. onMouseUp(event: SMouseEvent): boolean {
  389. // grabItem 不为 null
  390. if (this.grabItem) {
  391. // 鼠标抬起时,如果grabItem为框选则删除框选item
  392. if (this.grabItem instanceof SRectSelectItem) {
  393. this.removeItem(this.grabItem);
  394. this.groupSelect(false);
  395. this.grabItem = null;
  396. // view 不为空
  397. if (this.view) {
  398. this.view.update();
  399. }
  400. return true;
  401. }
  402. return this.grabItem.onMouseUp(event);
  403. }
  404. return super.onMouseUp(event);
  405. }
  406. /**
  407. * 复制
  408. */
  409. copy(): void {
  410. const itemList = this.save(false);
  411. // itemList 复制数据不为空
  412. if (itemList) {
  413. // 删除对应得id
  414. itemList.markers.map((item: any) => {
  415. delete item.id;
  416. delete item.graphId;
  417. delete item.markerId;
  418. return item;
  419. });
  420. // 删除对应得id
  421. itemList.nodes.map((item: any) => {
  422. delete item.id;
  423. delete item.graphId;
  424. delete item.markerId;
  425. return item;
  426. });
  427. // 删除对应得id
  428. itemList.relations.map((item: any) => {
  429. delete item.id;
  430. delete item.graphId;
  431. delete item.markerId;
  432. return item;
  433. });
  434. this.copyString = itemList;
  435. // 获取input dom
  436. const input = document.createElement("input");
  437. input.setAttribute("id", "COPYINPUT");
  438. input.value = JSON.stringify(this.copyString);
  439. sessionStorage.setItem("copyString", input.value);
  440. document.body.appendChild(input);
  441. input.select();
  442. document.execCommand("copy");
  443. input.style.display = "none";
  444. console.log(input.value, Date.now());
  445. document.body.removeChild(input);
  446. }
  447. }
  448. /**
  449. * 添加多个item命令
  450. *
  451. * @param itemList 鼠标事件对象
  452. */
  453. addListCommand(itemList: SGraphEdit[]): void {
  454. this.undoStack.push(new SGraphAddListCommand(this, itemList));
  455. }
  456. /**
  457. * 图例置顶、置底
  458. *
  459. * @param type 设置类型
  460. */
  461. setOrder(type: string) {
  462. this.selectContainer.setOrder(SOrderSetType[type]);
  463. }
  464. /**
  465. * 设置管线结束锚点
  466. */
  467. setTipeEndanchor(event: SMouseEvent): void {
  468. if (this.grabItem instanceof SBasePipe) {
  469. const anc = this.clickIsAnchor(event);
  470. if (anc) {
  471. const p = anc.mapToScene(0, 0);
  472. anc.isConnected = true;
  473. event.x = p.x;
  474. event.y = p.y;
  475. // 判断当前是否为编辑状态
  476. if (this.grabItem.status == SItemStatus.Create) {
  477. // pointList 长度不能为空
  478. if (this.grabItem.pointList.length) {
  479. this.grabItem.endAnchor = anc;
  480. anc.parent?.connect(
  481. "changePos",
  482. this.grabItem,
  483. this.grabItem.changePos
  484. );
  485. }
  486. this.grabItem.anchor2Id = anc.id;
  487. this.grabItem.node2Id = anc.parent.nodeId;
  488. this.grabItem.onMouseDown(event);
  489. this.grabItem.status = SItemStatus.Normal;
  490. this.finishCreated(this.grabItem);
  491. return;
  492. }
  493. }
  494. this.grabItem.onMouseDown(event);
  495. }
  496. }
  497. /**
  498. * 获取item (常用与场景外的调用F)
  499. *
  500. * @param isAll 是否为全部item数据
  501. * @returns 返回保存的数据接口
  502. */
  503. save(isAll: boolean = true): any {}
  504. }