SBaseEditScene.ts 17 KB

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