TemplateEditor.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. import {Template, Container, MainPipe} from './DiagramModel';
  2. import {Point, BackgroundPaniter, ViewTool} from './UIUtils';
  3. import {ContainerRefPoint} from './ContainerRefPoint';
  4. import {Editor, Selection} from './Editor';
  5. /**
  6. * 模板编辑器
  7. * @author zhaoyk
  8. */
  9. export class TemplateEditor extends Editor {
  10. private util: EditUtil;
  11. templateData: Template;
  12. tmpMainPipe:Array<Array<Point>>;
  13. currentTmpMainPipe:Array<Point>;
  14. refPoints: any;
  15. currentRefPoint: any;
  16. protected initCanvasSize(): Point{
  17. return new Point(2500, 2500);
  18. }
  19. addListeners(): void {
  20. this.canvas.addEventListener('click', event=>{this.onClick(event)});
  21. this.container.addEventListener("mousemove", event=>{this.onMouseMove(event)});
  22. }
  23. showData(template?: any): void {
  24. this.templateData = (<Template>template);
  25. this.selection = new Selection();
  26. this.setState(this.getState());
  27. this.util = new EditUtil(this);
  28. this.refPoints = {};
  29. this.redraw();
  30. }
  31. setState(state: number): void{
  32. this.state = state;
  33. if(this.state == 9)
  34. this.tmpMainPipe = new Array<Array<Point>>();
  35. else
  36. this.tmpMainPipe = null;
  37. this.currentTmpMainPipe = null;
  38. this.currentRefPoint = null;
  39. }
  40. redraw():void {
  41. this.beforeRedraw();
  42. const root = this.templateData.frame;
  43. this.util.prepareParent(root);
  44. if(this.templateData.scatteredContainers)
  45. this.templateData.scatteredContainers.forEach(con => this.util.prepareParent(con));
  46. //绘制排列定位容器
  47. this.drawContainer(root);
  48. //绘制自由定位容器
  49. if(this.templateData.scatteredContainers) {
  50. const p = new Point(root.location.x, root.location.y);
  51. p.y += root.size.y;
  52. this.templateData.scatteredContainers.forEach(con => {
  53. p.y += 20;
  54. con.location = new Point(p.x, p.y);
  55. this.drawContainer(con, true);
  56. p.y += con.size.y;
  57. });
  58. }
  59. //绘制干管
  60. if(this.templateData.mainPipes) {
  61. this.templateData.mainPipes.forEach(item => {
  62. let color = "#5783FA";
  63. if(item.bindEquipment)
  64. color = "#000000";
  65. this.ctx.strokeStyle = color; //#FA943B
  66. this.ctx.setLineDash([]);
  67. if(this.getSelComp() == item)
  68. this.ctx.lineWidth = 2;
  69. else
  70. this.ctx.lineWidth = 1;
  71. this.ctx.beginPath();
  72. for(const arr of item.locationPath){
  73. var iter = 0;
  74. for(var p of arr) {
  75. p = this.util.toCanvas(p);
  76. if(iter == 0)
  77. this.ctx.moveTo(p.x, p.y);
  78. else
  79. this.ctx.lineTo(p.x, p.y);
  80. iter++;
  81. }
  82. }
  83. this.ctx.stroke();
  84. this.ctx.closePath();
  85. });
  86. }
  87. //干管绘制过程
  88. if(this.tmpMainPipe) {
  89. let color = "#5783FA";
  90. for(const line of this.tmpMainPipe) {
  91. var pre: Point = null;
  92. for(const p of line) {
  93. this.ctx.beginPath();
  94. //画点
  95. ViewTool.paintPoint(this.ctx, p, color, true);
  96. //画线
  97. if(pre != null) {
  98. this.ctx.strokeStyle = color;
  99. this.ctx.lineWidth = 1;
  100. this.ctx.setLineDash([]);
  101. this.ctx.moveTo(pre.x, pre.y);
  102. this.ctx.lineTo(p.x, p.y);
  103. this.ctx.stroke();
  104. }
  105. this.ctx.closePath();
  106. pre = p;
  107. }
  108. }
  109. }
  110. //干管绘制的定位参考点
  111. if(this.currentRefPoint) {
  112. this.ctx.beginPath();
  113. ViewTool.paintPoint(this.ctx, this.currentRefPoint.location, "#ff5500", true);
  114. this.ctx.closePath();
  115. }
  116. }
  117. private drawContainer(con:Container, drawLiberty?:boolean) {
  118. if(!drawLiberty && con.position.absolute)
  119. return;
  120. const liberty = con.position.absolute;
  121. const location = !liberty ? this.util.locationOnCanvas(con) : this.util.toCanvas(con.location);
  122. if(!liberty && con.parent != null)
  123. this.refPoints[con.id] = ContainerRefPoint.getRefPoints(con.id, location, con.size);
  124. const equip = con.equipmentTypes && con.equipmentTypes.length > 0;
  125. const color = equip ? (!liberty ? "#000000" : "#2a7652") : (!liberty ? "#9b9ea3": "#42B983");
  126. const dash = equip ? [] : [3, 2];
  127. this.ctx.lineWidth = 1;
  128. this.ctx.setLineDash(dash);
  129. this.ctx.strokeStyle = color;
  130. this.ctx.beginPath();
  131. this.ctx.rect(location.x, location.y, con.size.x, con.size.y);
  132. this.ctx.stroke();
  133. if(this.getSelComp() == con) {
  134. this.ctx.fillStyle = "rgba(0, 127, 255, 0.1)";
  135. this.ctx.fill();
  136. }
  137. if(con.dynGroup && con.parent){
  138. var mark = "";
  139. if(con.parent.layout.layout == 1)
  140. mark = "↓";
  141. else if(con.parent.layout.layout == 2)
  142. mark = "→";
  143. if(mark.length > 0)
  144. ViewTool.drawText(this.ctx, mark, new Point(location.x, location.y), con.size);
  145. }
  146. if(equip) {
  147. var info = "";
  148. if(con.name)
  149. info += con.name + "\n";
  150. info += "[ " + con.equipmentTypes + " ]";
  151. if(con.dataFilter)
  152. info += ViewTool.filterToStr(con.dataFilter);
  153. if(con.equipPack)
  154. info += " <打包>";
  155. ViewTool.drawText(this.ctx, info, new Point(location.x + 10, location.y + 10), con.size);
  156. var layoutInfo = "";
  157. var offset: Point;
  158. if(con.layout.layout == 1) {
  159. layoutInfo = "---\n---\n---";
  160. offset = new Point(-5, -30);
  161. } else if(con.layout.layout == 2) {
  162. layoutInfo = "| | |";
  163. offset = new Point(-10, -10);
  164. }
  165. ViewTool.drawText(this.ctx, layoutInfo, new Point(location.x + (con.size.x / 2) + offset.x , location.y + (con.size.y / 2) + offset.y), new Point(con.size.x / 2, con.size.y / 2));
  166. }
  167. if(con.children)
  168. con.children.forEach(item => this.drawContainer(<Container>item));
  169. }
  170. // private redrawOnScroll(_this) {
  171. // const top = _this.container.scrollTop;
  172. // const left = _this.container.scrollLeft;
  173. // _this.canvas.style.top = top + 'px';
  174. // _this.canvas.style.left = left + 'px';
  175. // _this.draw(_this.mapData);
  176. // }
  177. private onClick(event): void {
  178. if(this.state != 9) { //selection
  179. var sel:any = this.util.findMainPipe(event.layerX, event.layerY);
  180. if(sel == null)
  181. sel = this.util.findContainer(event.layerX, event.layerY);
  182. if(sel != this.getSelComp)
  183. this.setSelComp(sel);
  184. } else { //paint main pipe
  185. if(this.currentTmpMainPipe == null) {
  186. this.currentTmpMainPipe = new Array<Point>();
  187. this.tmpMainPipe.push(this.currentTmpMainPipe);
  188. }
  189. const point = new Point(event.layerX, event.layerY);
  190. this.adjustPointForMp(point);
  191. this.currentTmpMainPipe.push(point);
  192. this.redraw();
  193. }
  194. }
  195. setSelComp(comp: any): void{
  196. this.selection.setSel(comp);
  197. this.redraw();
  198. this.editorPart.onSelectionChange();
  199. }
  200. getSelComp(): any {
  201. if(!this.selection)
  202. return null;
  203. return this.selection.getSel();
  204. }
  205. buildSelInfo(){
  206. var info = null;
  207. const sel = this.getSelComp();
  208. if(sel != null) {
  209. info = 'id: ' + sel.id;
  210. if(sel.name)
  211. info += ' | 名称: ' + sel.name;
  212. if(sel.layout) {
  213. if(sel.layout.layout == 1)
  214. info += ' | 布局方式: 行式';
  215. else if(sel.layout.layout == 2)
  216. info += ' | 布局方式: 列式';
  217. }
  218. if(sel.equipmentTypes && sel.equipmentTypes.length > 0){
  219. info += ' | 设备类型: ' + sel.equipmentTypes;
  220. }
  221. if(sel.dataFilter) {
  222. info += ' | 过滤条件: '
  223. info += ViewTool.filterToStr(sel.dataFilter);
  224. }
  225. if(sel.equipPack)
  226. info += ' | <打包>';
  227. if(sel.locationPath){
  228. var str = '';
  229. const arr:Array<Array<Point>> = new Array<Array<Point>>();
  230. for(const line of sel.locationPath) {
  231. const ps:Array<Point> = new Array<Point>();
  232. arr.push(ps);
  233. line.forEach(item => {
  234. ps.push(this.util.toCanvas(item));
  235. });
  236. if(str.length > 0)
  237. str += ", ";
  238. str += ViewTool.pointsToStr(ps);
  239. }
  240. info += ' | ' + str;
  241. }
  242. }
  243. if(info == null)
  244. info = '~';
  245. return info;
  246. }
  247. getState(): number {
  248. const sel = this.getSelComp();
  249. if(!sel)
  250. return 0;
  251. if(sel.locationPath)
  252. return 2;
  253. return 1;
  254. }
  255. getCompById(id: string): any {
  256. if(!id)
  257. return null;
  258. if(this.templateData.mainPipes) {
  259. for(const mp of this.templateData.mainPipes) {
  260. if(mp.id == id)
  261. return mp;
  262. }
  263. }
  264. return this.getConById(id);
  265. }
  266. getConById(id:string): Container {
  267. return this.findCon(id, this.templateData.frame);
  268. }
  269. private findCon(id:string, con: Container): Container {
  270. if(con.id == id)
  271. return con;
  272. for(const sub of con.children) {
  273. const rtn = this.findCon(id, <Container>sub);
  274. if(rtn != null)
  275. return rtn;
  276. }
  277. return null;
  278. }
  279. //干管绘制时,自动调整横平竖直
  280. private adjustPointForMp(point: Point) {
  281. if(this.currentTmpMainPipe && this.currentTmpMainPipe.length > 0) {
  282. const pre = this.currentTmpMainPipe[this.currentTmpMainPipe.length - 1];
  283. if(Math.abs(pre.x - point.x) < Math.abs(pre.y - point.y))
  284. point.x = pre.x;
  285. else
  286. point.y = pre.y;
  287. }
  288. }
  289. private onMouseMove(event): void {
  290. if(this.state == 9) {
  291. const point = new Point(event.layerX, event.layerY);
  292. this.adjustPointForMp(point);
  293. //显示当前坐标位置
  294. this.editorPart.dynInfo = ViewTool.pointToStr(point);
  295. //计算定位参考点
  296. var min: number = Number.MAX_VALUE;
  297. var nearRp: any;
  298. for(const cId in this.refPoints) {
  299. const rps = this.refPoints[cId];
  300. if(rps && rps.length) {
  301. for(const rp of rps){
  302. const p1 = rp.location;
  303. const distance = Math.sqrt(Math.pow(p1.x - point.x, 2) + Math.pow(p1.y - point.y, 2));
  304. if(distance < min) {
  305. min = distance;
  306. nearRp = rp;
  307. }
  308. }
  309. }
  310. }
  311. this.currentRefPoint = nearRp;
  312. this.redraw();
  313. }
  314. }
  315. }
  316. class EditUtil {
  317. private editor:TemplateEditor;
  318. private template:Template;
  319. constructor(editor:TemplateEditor) {
  320. this.editor = editor;
  321. this.template = editor.templateData;
  322. }
  323. prepareParent(con:Container) {
  324. con.children.forEach(item => {
  325. item.parent = con;
  326. this.prepareParent(<Container>item);
  327. });
  328. }
  329. locationOnDiagram(con:Container): Point {
  330. const p:Point = new Point(0, 0);
  331. var c:Container = con;
  332. while (c != null){
  333. p.x += c.location.x;
  334. p.y += c.location.y;
  335. c = c.parent;
  336. }
  337. return p;
  338. }
  339. locationOnCanvas(con:Container): Point {
  340. return this.toCanvas(this.locationOnDiagram(con));
  341. }
  342. toCanvas(point:Point): Point {
  343. return new Point(point.x + this.editor.margin, point.y + this.editor.margin);
  344. }
  345. findContainer(x:number, y:number): Container {
  346. var rtn = this.findCon(x, y, this.template.frame);
  347. if(!rtn && this.editor.templateData.scatteredContainers) {
  348. for(const con of this.editor.templateData.scatteredContainers){
  349. rtn = this.findCon(x, y, con);
  350. if(rtn)
  351. break;
  352. }
  353. }
  354. return rtn;
  355. }
  356. private findCon(x:number, y:number, target:Container): Container {
  357. if(this.containsPoint(target, x, y)){
  358. for(const item of target.children) {
  359. const c = this.findCon(x, y, <Container>item);
  360. if(c != null)
  361. return c;
  362. }
  363. return target;
  364. }
  365. return null;
  366. }
  367. containsPoint(con:Container, x:number, y:number):boolean{
  368. if(con.location){
  369. const point = con.position.absolute ? this.toCanvas(con.location) : this.locationOnCanvas(con);
  370. return x >= point.x && y >= point.y && x <= point.x + con.size.x && y <= point.y + con.size.y;
  371. }
  372. return false;
  373. }
  374. findMainPipe(x:number, y:number): any {
  375. if(this.template.mainPipes) {
  376. for(const mp of this.template.mainPipes){
  377. for(const line of mp.locationPath) {
  378. var pre: Point = null;
  379. for(var point of line) {
  380. point = this.toCanvas(point);
  381. if(pre != null) {
  382. var x1:number;
  383. var y1:number;
  384. var x2:number;
  385. var y2:number;
  386. const scope = 3;
  387. if(pre.y == point.y) { //水平
  388. y1 = pre.y - scope;
  389. y2 = pre.y + scope;
  390. x1 = Math.min(pre.x, point.x);
  391. x2 = Math.max(pre.x, point.x);
  392. } else { //垂直
  393. x1 = pre.x - scope;
  394. x2 = pre.x + scope;
  395. y1 = Math.min(pre.y, point.y);
  396. y2 = Math.max(pre.y, point.y);
  397. }
  398. if(x >= x1 && y >= y1 && x <= x2 && y <= y2)
  399. return mp;
  400. }
  401. pre = point;
  402. }
  403. }
  404. }
  405. }
  406. return null;
  407. }
  408. }