SBaseEditScene.ts 17 KB

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