import {Diagram, Template, EquipmentNode, Line, Comp, Container, MainPipe, Legend, Anchor, Point4Anchor} from './DiagramModel'; import {Point, BackgroundPaniter, ViewTool} from './UIUtils'; import {Editor, Selection} from './Editor'; /** * 系统图编辑器,演示版本 * @author zhaoyk */ export class DiagramEditor extends Editor { private util: EditUtil; diagram: Diagram; templateData: Template; libertyCons: Array; //自由定位的容器 tmpMainPipe:Array>; currentTmpMainPipe:Array; showData(data?: any): void { this.diagram = (data); this.templateData = this.diagram.template; this.selection = new Selection(); this.setState(this.getState()); this.util = new EditUtil(this); this.redraw(); } protected initCanvasSize(): Point { return new Point(3500, 3500); } addListeners():void { this.canvas.addEventListener('click', event=>{this.onClick(event)}); this.container.addEventListener("mousemove", event=>{this.onMouseMove(event)}); } setState(state: number): void{ this.state = state; if(this.state == 9) this.tmpMainPipe = new Array>(); else this.tmpMainPipe = null; this.currentTmpMainPipe = null; } redraw(): void { this.beforeRedraw(); if(!this.diagram.template) return; this.libertyCons = new Array(); const root = this.templateData.frame; this.util.prepareParent(root); //绘制排列定位容器 this.drawContainer(root); //绘制自由定位容器 const p = new Point(root.location.x, root.location.y); p.y += root.size.y; this.libertyCons.forEach(con => { p.y += 20; con.location = new Point(p.x, p.y); this.drawContainer(con, true); p.y += con.size.y; }); //绘制干管 if(this.templateData.mainPipes) { this.templateData.mainPipes.forEach(item => { this.ctx.strokeStyle = "#000000"; this.ctx.setLineDash([]); this.ctx.lineWidth = 2; if(this.getSelComp() == item) this.ctx.strokeStyle = "#5783FA"; this.ctx.beginPath(); for(const arr of item.locationPath){ var iter = 0; for(var p of arr) { p = this.util.toCanvas(p); if(iter == 0) this.ctx.moveTo(p.x, p.y); else this.ctx.lineTo(p.x, p.y); iter++; } } this.ctx.stroke(); }); } //绘制连线 if(this.diagram.lines) { this.diagram.lines.forEach(line => { if(line.locationPath) { this.ctx.strokeStyle = "#000000"; this.ctx.setLineDash([]); this.ctx.lineWidth = 1; this.ctx.beginPath(); var iter = 0; for(var p of line.locationPath){ p = this.util.toCanvas(p); if(iter == 0) this.ctx.moveTo(p.x, p.y); else this.ctx.lineTo(p.x, p.y); iter++; } this.ctx.stroke(); } }); } } private drawContainer(con:Container, drawLiberty?:boolean) { if(!drawLiberty && con.position.absolute) return; if(con.size.x == 0 && con.size.y == 0) return; const liberty = con.position.absolute; const location = !liberty ? this.util.locationOnCanvas(con) : this.util.toCanvas(con.location); const equip = con.equipmentTypes && con.equipmentTypes.length > 0; var color = !liberty ? "#9b9ea3": "#42B983"; var dash = [3, 2]; if(equip) { this.ctx.lineWidth = 1; this.ctx.setLineDash(dash); this.ctx.strokeStyle = color; this.ctx.beginPath(); this.ctx.rect(location.x, location.y, con.size.x, con.size.y); this.ctx.closePath(); if(this.getSelComp() == con) { this.ctx.fillStyle = "rgba(0, 127, 255, 0.1)"; this.ctx.fill(); } this.ctx.stroke(); } if(con.children) con.children.forEach(item => { if(item.compType == 'container') this.drawContainer(item); else if(item.compType == 'equipmentNode') this.drawEquipNode(item); else if(item.compType == 'packNode') this.drawEquipNode(item); }); } private drawEquipNode(node: EquipmentNode): void { const location = this.util.locationOnCanvas(node); this.ctx.lineWidth = 1; this.ctx.setLineDash([]); this.ctx.strokeStyle = "#000000"; this.ctx.beginPath(); this.ctx.rect(location.x, location.y, node.size.x, node.size.y); if(this.getSelComp() == node) { this.ctx.fillStyle = "rgba(0, 127, 255, 0.1)"; this.ctx.fill(); } this.ctx.stroke(); if(node.anchorLocations) { for(const code in node.anchorLocations) { this.ctx.beginPath(); var p: Point = node.anchorLocations[code]; p = new Point(p.x + location.x, p.y + location.y); ViewTool.paintPoint(this.ctx, p, '#000000', true); } } if(node.label) { const lbl = node.label; ViewTool.drawText(this.ctx, lbl.content, new Point(location.x + lbl.location.x, location.y + lbl.location.y), node.size); } } // private redrawOnScroll(_this) { // const top = _this.container.scrollTop; // const left = _this.container.scrollLeft; // _this.canvas.style.top = top + 'px'; // _this.canvas.style.left = left + 'px'; // _this.draw(_this.mapData); // } private onClick(event): void { if(this.state != 9) { //selection var sel:any = this.util.findMainPipe(event.layerX, event.layerY); if(sel == null) sel = this.util.findComp(event.layerX, event.layerY); if(sel != this.getSelComp) this.setSelComp(sel); } else { //paint main pipe if(this.currentTmpMainPipe == null) { this.currentTmpMainPipe = new Array(); this.tmpMainPipe.push(this.currentTmpMainPipe); } const point = new Point(event.layerX, event.layerY); this.adjustPointForMp(point); this.currentTmpMainPipe.push(point); this.redraw(); } } setSelComp(comp: any): void{ this.selection.setSel(comp); this.redraw(); this.editorPart.onSelectionChange(); } getSelComp(): any { if(!this.selection) return null; return this.selection.getSel(); } buildSelInfo(){ var info = null; const sel = this.getSelComp(); if(sel != null) { if(sel.compType == "equipmentNode") { info = '设备id: ' + sel.dataObject.id; info += ' | 设备类型: ' + sel.dataObject.classCode; info += ' | 设备名称: ' + sel.dataObject.name; } else { info = 'id: ' + sel.id; if(sel.name) info += ' | 名称: ' + sel.name; if(sel.layout) { if(sel.layout.layout == 1) info += ' | 布局方式: 行式'; else if(sel.layout.layout == 2) info += ' | 布局方式: 列式'; } if(sel.equipmentTypes && sel.equipmentTypes.length > 0){ info += ' | 设备类型: ' + sel.equipmentTypes; } if(sel.locationPath){ var str = ''; const arr:Array> = new Array>(); for(const line of sel.locationPath) { const ps:Array = new Array(); arr.push(ps); line.forEach(item => { ps.push(this.util.toCanvas(item)); }); if(str.length > 0) str += ", "; str += ViewTool.pointsToStr(ps); } info += ' | ' + str; } } } if(info == null) info = '~'; return info; } getState(): number { const sel = this.getSelComp(); if(!sel) return 0; if(sel.locationPath) return 2; return 1; } getCompById(id: string): any { if(!id) return null; if(this.templateData.mainPipes) { for(const mp of this.templateData.mainPipes) { if(mp.id == id) return mp; } } return this.getConById(id); } getConById(id:string): Container { return this.findCon(id, this.templateData.frame); } private findCon(id:string, con: Container): Container { if(con.id == id) return con; for(const sub of con.children) { if(sub.compType == 'container') { const rtn = this.findCon(id, sub); if(rtn != null) return rtn; } } return null; } //干管绘制时,自动调整横平竖直 private adjustPointForMp(point: Point) { if(this.currentTmpMainPipe && this.currentTmpMainPipe.length > 0) { const pre = this.currentTmpMainPipe[this.currentTmpMainPipe.length - 1]; if(Math.abs(pre.x - point.x) < Math.abs(pre.y - point.y)) point.x = pre.x; else point.y = pre.y; } } private onMouseMove(event): void { if(this.state == 9) { const point = new Point(event.layerX, event.layerY); this.adjustPointForMp(point); //显示当前坐标位置 this.editorPart.dynInfo = ViewTool.pointToStr(point); this.redraw(); } } } class EditUtil { private editor:DiagramEditor; private template:Template; constructor(editor:DiagramEditor) { this.editor = editor; this.template = editor.templateData; } prepareParent(con:Container) { if(con.children) { con.children.forEach(item => { item.parent = con; if(item.compType == 'container') { this.prepareParent(item); if(item.position.absolute) this.editor.libertyCons.push(item); } }); } } clearParent(con:Container){ con.parent = null; con.children.forEach(item => { item.parent = null; if(item.compType == 'container') this.clearParent(item); }); } locationOnDiagram(con:Comp): Point { const p:Point = new Point(0, 0); var c = con; while (c != null){ p.x += c.location.x; p.y += c.location.y; c = c.parent; } return p; } locationOnCanvas(con:Comp): Point { return this.toCanvas(this.locationOnDiagram(con)); } toCanvas(point:Point): Point { return new Point(point.x + this.editor.margin, point.y + this.editor.margin); } findComp(x:number, y:number): Comp { var rtn = this.tryFindComp(x, y, this.template.frame); if(!rtn) { for(const con of this.editor.libertyCons){ rtn = this.tryFindComp(x, y, con); if(rtn) break; } } return rtn; } private tryFindComp(x:number, y:number, target:Comp): Comp { if(this.containsPoint(target, x, y)){ if(target.compType == 'container') { for(const item of (target).children) { const c = this.tryFindComp(x, y, item); if(c != null) return c; } } return target; } return null; } containsPoint(con:Comp, x:number, y:number):boolean{ if(con.location){ var point; if(con.position && con.position.absolute) point = this.toCanvas(con.location) else point = this.locationOnCanvas(con); return x >= point.x && y >= point.y && x <= point.x + con.size.x && y <= point.y + con.size.y; } return false; } findMainPipe(x:number, y:number): any { if(this.template.mainPipes) { for(const mp of this.template.mainPipes){ for(const line of mp.locationPath) { var pre: Point = null; for(var point of line) { point = this.toCanvas(point); if(pre != null) { var x1:number; var y1:number; var x2:number; var y2:number; const scope = 3; if(pre.y == point.y) { //水平 y1 = pre.y - scope; y2 = pre.y + scope; x1 = Math.min(pre.x, point.x); x2 = Math.max(pre.x, point.x); } else { //垂直 x1 = pre.x - scope; x2 = pre.x + scope; y1 = Math.min(pre.y, point.y); y2 = Math.max(pre.y, point.y); } if(x >= x1 && y >= y1 && x <= x2 && y <= y2) return mp; } pre = point; } } } } return null; } }