From dd3dc17622ab7b14e84e355149e642c5247fab32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=8C=AF=E5=8D=87?= <359059686@qq.com> Date: Sat, 23 Jan 2021 18:27:53 +0800 Subject: [PATCH 1/3] axSelection,axMessageSystem --- .../working-area/model/axImageShapeTest.ts | 11 - src/app/working-area/model/axLegend.ts | 1 - src/app/working-area/model/axMessageSystem.ts | 90 +++++ .../working-area/model/axRectangleShape.ts | 24 +- src/app/working-area/model/axSelection.ts | 48 +++ src/app/working-area/model/axShape.ts | 58 +-- src/app/working-area/model/messageSystem.ts | 37 -- .../working-area/working-area.component.ts | 347 +++++++----------- 8 files changed, 321 insertions(+), 295 deletions(-) delete mode 100644 src/app/working-area/model/axImageShapeTest.ts create mode 100644 src/app/working-area/model/axMessageSystem.ts create mode 100644 src/app/working-area/model/axSelection.ts delete mode 100644 src/app/working-area/model/messageSystem.ts diff --git a/src/app/working-area/model/axImageShapeTest.ts b/src/app/working-area/model/axImageShapeTest.ts deleted file mode 100644 index 81c141c..0000000 --- a/src/app/working-area/model/axImageShapeTest.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { AxRectangleShape } from "./axRectangleShape"; - -export class AxImageShapeTest extends AxRectangleShape{ - /** - * - */ - constructor(x:number,y:number,width:number,height:number) { - super(x,y,width,height); - - } -} \ No newline at end of file diff --git a/src/app/working-area/model/axLegend.ts b/src/app/working-area/model/axLegend.ts index a886fd3..f2158ac 100644 --- a/src/app/working-area/model/axLegend.ts +++ b/src/app/working-area/model/axLegend.ts @@ -429,7 +429,6 @@ export class AxLegend extends AxShape { */ public drawBorder(scale: number) { const visible = this.upLeft.visible; - console.log(visible); this.setPointVisiable(false); super.drawBorder(scale); diff --git a/src/app/working-area/model/axMessageSystem.ts b/src/app/working-area/model/axMessageSystem.ts new file mode 100644 index 0000000..1451f9c --- /dev/null +++ b/src/app/working-area/model/axMessageSystem.ts @@ -0,0 +1,90 @@ +/** + * 事件系统 + */ +export class AxMessageSystem { + /** 监听数组 */ + private static listeners = {}; + + /** + * 注册事件 + * @param name 事件名称 + * @param callback 回调函数 + * @param context 上下文 + */ + public static addListener(name: string, callback: () => void, context: any) { + const observers: Observer[] = AxMessageSystem.listeners[name]; + if (!observers) { + AxMessageSystem.listeners[name] = []; + } + AxMessageSystem.listeners[name].push(new Observer(callback, context)); + } + + /** + * 移除事件 + * @param name 事件名称 + * @param callback 回调函数 + * @param context 上下文 + */ + public static removeListener(name: string, callback: () => void, context: any) { + const observers: Observer[] = AxMessageSystem.listeners[name]; + if (!observers) { return; } + const length = observers.length; + for (let i = 0; i < length; i++) { + const observer = observers[i]; + if (observer.compar(context)) { + observers.splice(i, 1); + break; + } + } + if (observers.length === 0) { + delete AxMessageSystem.listeners[name]; + } + } + + /** + * 发送事件 + * @param name 事件名称 + */ + public static send(name: string, ...args: any[]) { + const observers: Observer[] = AxMessageSystem.listeners[name]; + if (!observers) { return; } + const length = observers.length; + for (let i = 0; i < length; i++) { + const observer = observers[i]; + observer.notify(name, ...args); + } + } +} + +/** + * 观察者 + */ +class Observer { + /** 回调函数 */ + private callback: () => void; + /** 上下文 */ + private context: any = null; + + constructor(callback: () => void, context: any) { + const self = this; + self.callback = callback; + self.context = context; + } + + /** + * 发送通知 + * @param args 不定参数 + */ + notify(...args: any[]): void { + const self = this; + self.callback.call(self.context, ...args); + } + + /** + * 上下文比较 + * @param context 上下文 + */ + compar(context: any): boolean { + return context === this.context; + } +} diff --git a/src/app/working-area/model/axRectangleShape.ts b/src/app/working-area/model/axRectangleShape.ts index 297ffdb..cf61f6c 100644 --- a/src/app/working-area/model/axRectangleShape.ts +++ b/src/app/working-area/model/axRectangleShape.ts @@ -1,21 +1,21 @@ -import { Sprite } from "pixi.js"; -import { Graphics } from "pixi.js"; -import { WorkingAreaComponent } from "../working-area.component"; -import { AxShape } from "./axShape"; +import { Sprite } from 'pixi.js'; +import { Graphics } from 'pixi.js'; +import { WorkingAreaComponent } from '../working-area.component'; +import { AxShape } from './axShape'; -export class AxRectangleShape extends AxShape{ +export class AxRectangleShape extends AxShape { /** * */ - constructor(x:number,y:number,width:number,height:number,assetData: any, workingArea: WorkingAreaComponent) { - super(assetData,workingArea); - this.beginFill(0x0000ff,1); - this.lineStyle(1, 0xff0000,1); + constructor(x: number, y: number, width: number, height: number, assetData: any, workingArea: WorkingAreaComponent) { + super(assetData, workingArea); + this.beginFill(0x0000ff, 1); + this.lineStyle(1, 0xff0000, 1); this.drawRect(x, y, width, height); this.endFill(); - - + + } - + } diff --git a/src/app/working-area/model/axSelection.ts b/src/app/working-area/model/axSelection.ts new file mode 100644 index 0000000..e61cd78 --- /dev/null +++ b/src/app/working-area/model/axSelection.ts @@ -0,0 +1,48 @@ +/** + * 选择器 + */ +export class AxSelection { + constructor() { + } + private objects: Set = new Set(); + // 获得第一个对象 + public first(): any { + if (this.objects.size > 0) { + return this.objects[0]; + } else { + return null; + } + } + // 获得所有对象 + public all() { + return this.objects; + } + // 获取集合长度 + public size(): number { + return this.objects.size; + } + // 添加对象 + public add(obj: any) { + this.objects.add(obj); + } + // 添加集合 + public addArray(array: any[]) { + array.forEach(item => { + this.objects.add(item); + }); + } + // 移除对象 + public delete(obj: any) { + this.objects.delete(obj); + } + // 移除集合 + public deleteArray(array: any[]) { + array.forEach(item => { + this.objects.delete(item); + }); + } + // 清空所有对象 + public clear() { + this.objects.clear(); + } +} diff --git a/src/app/working-area/model/axShape.ts b/src/app/working-area/model/axShape.ts index 27c1773..2d032d5 100644 --- a/src/app/working-area/model/axShape.ts +++ b/src/app/working-area/model/axShape.ts @@ -8,7 +8,7 @@ import { WorkingAreaComponent } from '../working-area.component'; */ export class AxShape extends Graphics { assetData: any; - pointTexture: PIXI.Texture = PIXI.Texture.from('assets/images/handle-main.png') + pointTexture: PIXI.Texture = PIXI.Texture.from('assets/images/handle-main.png'); workingArea: WorkingAreaComponent; // 可以被移动的 moveable = true; @@ -20,7 +20,7 @@ export class AxShape extends Graphics { showName = true; // 边框 border: PIXI.Graphics = new PIXI.Graphics(); - + constructor(assetData: any, workingArea: WorkingAreaComponent) { super(); this.border.visible = false; @@ -35,7 +35,7 @@ export class AxShape extends Graphics { .on('pointerdown', event => { event.stopPropagation(); if (this.selectable) { - this.workingArea.selection.selectOne(this); + this.workingArea.selectSingle(this); } if (this.moveable) { event.currentTarget.data = event.data; @@ -86,14 +86,14 @@ export class AxShape extends Graphics { }); } redraw(): void { - + } - refresh(): void{ - + refresh(): void { + } public setItemScale(scale: number) { - + } public showBorder() { @@ -110,10 +110,10 @@ export class AxShape extends Graphics { * @param value 显示状态 */ public setPointVisiable(value: boolean) { - + } /** - * + * * @param rect 画边框 */ public drawBorder(scale: number) { @@ -127,14 +127,14 @@ export class AxShape extends Graphics { this.border.lineStyle(scale * 1, 0x00a8ff); - var spaceLength = scale * 1; - var lineLenght = rect.width + 0.5 + 0.5; - var dashLength = scale*( lineLenght +spaceLength - Math.floor((rect.width + rect.height)/2 / 4.1))/Math.floor((rect.width + rect.height)/2 / 4.1); - this.drawDash(this.border, p1.x -0.5*scale, p1.y, p2.x + 0.5*scale, p2.y,dashLength,spaceLength); - this.drawDash(this.border, p2.x, p2.y -0.5*scale, p3.x, p3.y + 0.5*scale, dashLength, spaceLength); - this.drawDash(this.border, p3.x+0.5*scale, p3.y, p4.x - 0.5*scale, p4.y, dashLength, spaceLength); - this.drawDash(this.border, p4.x, p4.y + 0.5*scale, p1.x, p1.y - 0.5*scale, dashLength, spaceLength); - + let spaceLength = scale * 1; + let lineLenght = rect.width + 0.5 + 0.5; + let dashLength = scale * ( lineLenght + spaceLength - Math.floor((rect.width + rect.height) / 2 / 4.1)) / Math.floor((rect.width + rect.height) / 2 / 4.1); + this.drawDash(this.border, p1.x - 0.5 * scale, p1.y, p2.x + 0.5 * scale, p2.y, dashLength, spaceLength); + this.drawDash(this.border, p2.x, p2.y - 0.5 * scale, p3.x, p3.y + 0.5 * scale, dashLength, spaceLength); + this.drawDash(this.border, p3.x + 0.5 * scale, p3.y, p4.x - 0.5 * scale, p4.y, dashLength, spaceLength); + this.drawDash(this.border, p4.x, p4.y + 0.5 * scale, p1.x, p1.y - 0.5 * scale, dashLength, spaceLength); + this.border.lineStyle(0, 0x0000ff); // this.border.beginFill(0x00ff00,0.1); this.border.moveTo(p1.x, p1.y); @@ -145,19 +145,19 @@ export class AxShape extends Graphics { // this.border.endFill(); } // 画虚线 - drawDash(target, x1, y1, x2, y2,dashLength = 5, spaceLength = 1) { - let x = x2 - x1; - let y = y2 - y1; + drawDash(target, x1, y1, x2, y2, dashLength = 5, spaceLength = 1) { + const x = x2 - x1; + const y = y2 - y1; let hyp = Math.sqrt((x) * (x) + (y) * (y)); - let units = hyp / (dashLength + spaceLength); - let dashSpaceRatio = dashLength / (dashLength + spaceLength); - let dashX = (x / units) * dashSpaceRatio; - let spaceX = (x / units) - dashX; - let dashY = (y / units) * dashSpaceRatio; - let spaceY = (y / units) - dashY; + const units = hyp / (dashLength + spaceLength); + const dashSpaceRatio = dashLength / (dashLength + spaceLength); + const dashX = (x / units) * dashSpaceRatio; + const spaceX = (x / units) - dashX; + const dashY = (y / units) * dashSpaceRatio; + const spaceY = (y / units) - dashY; target.moveTo(x1, y1); - + while (hyp > 0) { x1 += dashX; y1 += dashY; @@ -200,7 +200,7 @@ export class AxShape extends Graphics { return new PIXI.Point(gravityLat, gravityLng); } // 计算线段中点坐标 - public getLineCenter(point1:PIXI.Point,point2:PIXI.Point) { - return new PIXI.Point((point1.x+point2.x)/2,(point1.y+point2.y)/2) + public getLineCenter(point1: PIXI.Point, point2: PIXI.Point) { + return new PIXI.Point((point1.x + point2.x) / 2, (point1.y + point2.y) / 2); } } diff --git a/src/app/working-area/model/messageSystem.ts b/src/app/working-area/model/messageSystem.ts deleted file mode 100644 index 322eef4..0000000 --- a/src/app/working-area/model/messageSystem.ts +++ /dev/null @@ -1,37 +0,0 @@ -class MyEvent extends CustomEvent { - public static readonly CMD: string = "EVENT_NAME"; - public constructor($type: string , $data: T ) { - super( $type , { detail: $data, bubbles: true, cancelable: true, composed: true }); - } -} - -class MyDispatch extends EventTarget { - private static _instance: MyDispatch; - public static get Instance(): MyDispatch { - if (!MyDispatch._instance) MyDispatch._instance = new MyDispatch(); - return MyDispatch._instance; - } - public send($data: T, $type: string = MyEvent.CMD): void { - const $event: CustomEvent = new MyEvent($type, $data); - this.dispatchEvent($event); - } -} - -class Test { - - public constructor() { - MyDispatch.Instance.addEventListener(MyEvent.CMD, this.onEvent as EventListener); - } - private onEvent($e: MyEvent): void { - console.log(`target ${$e.target}`); - console.log(`name: ${$e.detail._name} , occupation: ${$e.detail._occupation}`); - } -} - -interface ITest { - _name: string; - _occupation: string; -} - -let $test: Test = new Test(); -MyDispatch.Instance.send({ _name: `Aonaufly`, _occupation: `it` }); diff --git a/src/app/working-area/working-area.component.ts b/src/app/working-area/working-area.component.ts index adaa4d7..1b05d4c 100644 --- a/src/app/working-area/working-area.component.ts +++ b/src/app/working-area/working-area.component.ts @@ -16,9 +16,9 @@ import { PropertyInfo } from './model/PropertyInfo'; import { AxPreviewImageShape } from './model/axPreviewImageShape'; import { AxArrowConnector } from './model/axArrowConnector'; import { AxLegend, Legend } from './model/axLegend'; -import { NullTemplateVisitor } from '@angular/compiler'; -import { AxRectangleShape } from './model/axRectangleShape'; import { AxGrid } from './model/axGrid'; +import { AxSelection } from './model/axSelection'; +import { AxMessageSystem } from './model/axMessageSystem'; @Component({ @@ -76,7 +76,7 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV /** * 选择器 */ - public selection: Selection = new Selection(this); + public readonly selection: AxSelection = new AxSelection(); /** * 当前鼠标的点 */ @@ -141,6 +141,9 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV * 网格 */ public grid: AxGrid = null; + // 是否按下Ctrl键 + isCtrlKeyClicked = false; + isMove = false; /** * 本软件版本号由四部分组成:<主版本号><次版本号><修订版本号><日期加希腊字母版本号> 例如:1.0.0.20210105_beta * Alpha版: 此版本表示该软件在此阶段主要是以实现软件功能为主,通常只在软件开发者内部交流,一般而言,该版本软件的Bug较多,需要继续修改。 @@ -157,12 +160,12 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV this.sayHello(); this.eventManager.addGlobalEventListener('window', 'keydown', (event: any) => { if (event.keyCode === 17) { - this.selection.isMultiselection = true; + this.isCtrlKeyClicked = true; } }); this.eventManager.addGlobalEventListener('window', 'keyup', (event: any) => { if (event.keyCode === 17) { - this.selection.isMultiselection = false; + this.isCtrlKeyClicked = false; this.rectToolGraphics.visible = false; this.rectToolGraphics.clear(); } @@ -171,23 +174,56 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV this.deleteSelectedShape(); } }); + // 消息系统事件监听 + AxMessageSystem.addListener(CanvasAction.selectionChanged, () => { + this.selection.all().forEach(item => { + item.showBorder(); + item.drawBorder(1 / this.backgroundImage.scale.x); + item.setPointVisiable(this.allowEdit); + }); + }, this); } /** * 删除选中的图标 */ public deleteSelectedShape() { - this.selection.objects.forEach(item => { - this.deleteShape(item); - }); - this.selection.deselectAll(); - } - /** - * - * @param obj 删除一个形状 - */ - public deleteShape(shape) { - if (this.allowEdit && this.canvasData.gameMode === shape.assetData.GameMode) { - this.emit('deleteIcon', shape); + if (this.selection.all().size > 0) { + this.selection.all().forEach(axShape => { + if (this.allowEdit && this.canvasData.gameMode === axShape.assetData.GameMode) { + // 删除图例对象 + const temp = this.backgroundImage.getChildByName('图例') as AxLegend; + if ( temp !== undefined + && temp !== null + && axShape.assetData.Name !== '图例') { + const itemLegend = new Legend(axShape.assetData.Name, axShape.assetData.ImageUrl, 1); + temp.deleteItem(itemLegend); + } + if (axShape.assetData.GameMode === GameMode.BasicInformation) { // 基本信息 + // 删除楼层数据 + delete this.canvasData.originaleveryStoreyData.data[axShape.assetData.Id]; + // 删除建筑数据 + delete this.canvasData.originalcompanyBuildingData.data[axShape.assetData.Id]; + } else if (axShape.assetData.GameMode === GameMode.Assignment) { // 处置预案 + delete this.canvasData.selectPanelPoint.Data.DefinedIncrement[axShape.assetData.Id]; + delete this.canvasData.selectPanelPoint.Data.Increment[axShape.assetData.Id]; + delete this.canvasData.selectPanelPoint.Data.Stock[axShape.assetData.Id]; + } else if (axShape.assetData.GameMode === GameMode.Examinee) { // 考生考试 + if (axShape.assetData.Tag === 1) { + // 删除楼层数据 + delete this.canvasData.examOriginaleveryStoreyData.data[axShape.assetData.Id]; + } else { + delete this.canvasData.selectPanelPoint.Data.DefinedIncrement[axShape.assetData.Id]; + delete this.canvasData.selectPanelPoint.Data.Increment[axShape.assetData.Id]; + delete this.canvasData.selectPanelPoint.Data.Stock[axShape.assetData.Id]; + } + } + this.backgroundImage.removeChild(axShape); + } + }); + this.selection.clear(); + this.emit('canvasDataChanged'); + this.canvasData.isChange = true; + AxMessageSystem.send(CanvasAction.selectionChanged); } } /** @@ -315,7 +351,7 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV this.app.stage.addChild(this.grid); this.grid.drawGrid(); this.grid.onMousemove = (evt, gridCoord) => { - console.log(gridCoord); + }; this.createBackgroundImage(); @@ -419,39 +455,7 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV * 删除图标事件(数据处理) */ this.on('deleteIcon', (axShape: AxShape) => { - // 删除图例对象 - const temp = this.backgroundImage.getChildByName('图例') as AxLegend; - if ( temp !== undefined - && temp !== null - && axShape.assetData.Name !== '图例') { - const itemLegend = new Legend(axShape.assetData.Name, axShape.assetData.ImageUrl, 1); - temp.deleteItem(itemLegend); - } - - if (axShape.assetData.GameMode === GameMode.BasicInformation) { // 基本信息 - // 删除楼层数据 - delete this.canvasData.originaleveryStoreyData.data[axShape.assetData.Id]; - // 删除建筑数据 - delete this.canvasData.originalcompanyBuildingData.data[axShape.assetData.Id]; - } else if (axShape.assetData.GameMode === GameMode.Assignment) { // 处置预案 - delete this.canvasData.selectPanelPoint.Data.DefinedIncrement[axShape.assetData.Id]; - delete this.canvasData.selectPanelPoint.Data.Increment[axShape.assetData.Id]; - delete this.canvasData.selectPanelPoint.Data.Stock[axShape.assetData.Id]; - } else if (axShape.assetData.GameMode === GameMode.Examinee) { // 考生考试 - if (axShape.assetData.Tag === 1) { - // 删除楼层数据 - delete this.canvasData.examOriginaleveryStoreyData.data[axShape.assetData.Id]; - } else { - delete this.canvasData.selectPanelPoint.Data.DefinedIncrement[axShape.assetData.Id]; - delete this.canvasData.selectPanelPoint.Data.Increment[axShape.assetData.Id]; - delete this.canvasData.selectPanelPoint.Data.Stock[axShape.assetData.Id]; - } - - } - this.backgroundImage.removeChild(axShape); - this.emit('canvasDataChanged'); - this.canvasData.isChange = true; }); } /** @@ -514,17 +518,16 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV }); } /** - * 设置高亮 + * 设置选中 + * 清空所有选择对象,选择ids集合元素 */ public setHighlight(ids: string[]): void { - this.selection.deselectAll(); + this.selection.clear(); ids.forEach(item => { - let obj = this.backgroundImage.getChildByName(item); - if (obj === null) { - obj = this.app.stage.getChildByName(item); - } - this.selection.select(obj); + const obj = this.backgroundImage.getChildByName(item); + this.selection.add(obj); }); + AxMessageSystem.send(''); } /** * 创建楼层图形 @@ -631,10 +634,9 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV .on('pointerdown', event => { if (event.data.button !== 0) { return; } console.log(this.backgroundImage.toLocal(this.mousePosition)); - if (!event.currentTarget.dragging && this.selection.isMultiselection === false) { - this.selection.deselectAll(); + if (!this.isMove && this.isCtrlKeyClicked === false) { event.currentTarget.data = event.data; - event.currentTarget.dragging = true; + this.isMove = true; event.currentTarget.dragPoint = event.data.getLocalPosition(event.currentTarget.parent); event.currentTarget.dragPoint.x -= event.currentTarget.x; event.currentTarget.dragPoint.y -= event.currentTarget.y; @@ -828,18 +830,17 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV // this.emit('backgroundScale', this.backgroundImage.scale.x); break; } - } else if (!event.currentTarget.dragging && this.selection.isMultiselection === true) { + } else if (!this.isMove && this.isCtrlKeyClicked === true) { this.rectToolGraphics.visible = true; - event.currentTarget.dragging = true; + this.isMove = true; this.initialScreenMousePos = this.backgroundImage.toLocal(this.mousePosition); this.finalScreenMousePos = this.backgroundImage.toLocal(this.mousePosition); } }) .on('pointerup', event => { - if (event.currentTarget.dragging) { - event.currentTarget.dragging = false; - event.currentTarget.data = null; - } + this.isMove = false; + event.currentTarget.data = null; + if (this.rectToolGraphics.visible === true) { this.backgroundImage.children.forEach(item => { if ( item instanceof AxImageShape @@ -850,26 +851,27 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV const rect1 = this.rectToolGraphics.getBounds(); const rect2 = item.getBounds(); if (this.isOverlap(rect1, rect2)) { - this.selection.select(item); + this.selection.add(item); } } }); this.rectToolGraphics.clear(); this.rectToolGraphics.visible = false; + AxMessageSystem.send(CanvasAction.selectionChanged); } }) .on('pointerupoutside', event => { - if (event.currentTarget.dragging) { - event.currentTarget.dragging = false; + if (this.isMove) { + this.isMove = false; event.currentTarget.data = null; } }) .on('pointermove', event => { - if (event.currentTarget.dragging && this.selection.isMultiselection === false) { + if (this.isMove && this.isCtrlKeyClicked === false) { const newPosition = event.currentTarget.data.getLocalPosition(event.currentTarget.parent); event.currentTarget.x = newPosition.x - event.currentTarget.dragPoint.x; event.currentTarget.y = newPosition.y - event.currentTarget.dragPoint.y; - } else if (event.currentTarget.dragging && this.selection.isMultiselection === true) { + } else if (this.isMove && this.isCtrlKeyClicked === true) { if (this.rectToolGraphics.visible === true) { this.finalScreenMousePos = this.backgroundImage.toLocal(this.mousePosition); } @@ -877,7 +879,7 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV }) .on('rightclick', event => { event.stopPropagation(); - this.selection.deselectAll(); + this.deselectAll(); this.setPaintMode(PaintMode.endPaint); }) .on('pointerover', (event) => { @@ -951,11 +953,11 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV * @param imageUrl * @param imageAngle */ - public async refresh(imageUrl: string = this.canvasData.selectStorey.imageUrl, imageAngle: number = this.canvasData.selectStorey.imageAngle): Promise { + public async refresh(imageUrl: string = this.canvasData.selectStorey.imageUrl, + imageAngle: number = this.canvasData.selectStorey.imageAngle): Promise { await this.refreshBackgroundImage(); - // 清空所有图形 - this.selection.deselectAll(); + this.deselectAll(); const itemList = []; this.backgroundImage.children.forEach(item => { if (item instanceof AxShape && item instanceof AxPreviewImageShape === false) { @@ -978,10 +980,10 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV * 加载无关联信息处置预案 * @data 处置预案数据 */ - public async loadNoRelevantInformationDisposalPlan(data:DisposalNodeData): Promise { - await this.refreshBackgroundImage(data.BackgroundImageUrl,data.BackgroundImageAngle); + public async loadNoRelevantInformationDisposalPlan(data: DisposalNodeData): Promise { + await this.refreshBackgroundImage(data.BackgroundImageUrl, data.BackgroundImageAngle); // 清空所有图形 - this.selection.deselectAll(); + this.deselectAll(); const itemList = []; this.backgroundImage.children.forEach(item => { if (item instanceof AxShape && item instanceof AxPreviewImageShape === false) { @@ -1142,7 +1144,7 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV */ public beginPaint() { console.log(this.canvasData.selectTemplateData); - this.selection.deselectAll(); + this.deselectAll(); this.setPaintMode(PaintMode.endPaint); this.setPaintMode(this.canvasData.selectTemplateData.interactiveMode); } @@ -1291,49 +1293,52 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV * 复制 */ public copy(): void { - this.copyData = []; - this.selection.objects.forEach(item => { - const newData = JSON.parse(JSON.stringify(item.assetData)); - this.copyData.push(newData); - }); + this.copyData = []; + this.selection.all().forEach(item => { + const newData = JSON.parse(JSON.stringify(item.assetData)); + this.copyData.push(newData); + }); } /** * 粘贴 */ public paste(companyId: string, buildingId: string, floorId: string): void { - this.copyData.forEach(item => { - item.Point = new PIXI.Point(item.Point.x + 5, item.Point.y + 5); - const newData = JSON.parse(JSON.stringify(item)); - newData.Id = ObjectID.default.generate(), - newData.CompanyId = companyId; - newData.BuildingId = buildingId; - newData.FloorId = floorId; - newData.Point = new PIXI.Point(item.Point.x + 5, item.Point.y + 5); - switch (item.InteractiveMode) { - case PaintMode.singlePointIcon: - const singleIcon = new AxImageShape(newData, this); - this.emit('createIcon', singleIcon); - break; - case PaintMode.lineIcon: - const lineIcon = new MultipointIcon(newData, this); - this.emit('createIcon', lineIcon); - break; - case PaintMode.polygonIcon: - const polygonIcon = new PolygonIcon(newData, this); - this.emit('createIcon', polygonIcon); - break; - case PaintMode.Pipeline: - if (item.Name === '距离') { - const wall = new AxArrowConnector(newData, this, true, true); - this.emit('createIcon', wall); - } else if (item.Name === '普通墙' || item.Name === '承重墙') { - const wall = new AxArrowConnector(newData, this, false, false); - this.emit('createIcon', wall); - } - break; - } - this.selection.select(this.backgroundImage.getChildByName(newData.Id)); - }); + if (this.copyData.length > 0) { + this.copyData.forEach(item => { + item.Point = new PIXI.Point(item.Point.x + 5, item.Point.y + 5); + const newData = JSON.parse(JSON.stringify(item)); + newData.Id = ObjectID.default.generate(), + newData.CompanyId = companyId; + newData.BuildingId = buildingId; + newData.FloorId = floorId; + newData.Point = new PIXI.Point(item.Point.x + 5, item.Point.y + 5); + switch (item.InteractiveMode) { + case PaintMode.singlePointIcon: + const singleIcon = new AxImageShape(newData, this); + this.emit('createIcon', singleIcon); + break; + case PaintMode.lineIcon: + const lineIcon = new MultipointIcon(newData, this); + this.emit('createIcon', lineIcon); + break; + case PaintMode.polygonIcon: + const polygonIcon = new PolygonIcon(newData, this); + this.emit('createIcon', polygonIcon); + break; + case PaintMode.Pipeline: + if (item.Name === '距离') { + const wall = new AxArrowConnector(newData, this, true, true); + this.emit('createIcon', wall); + } else if (item.Name === '普通墙' || item.Name === '承重墙') { + const wall = new AxArrowConnector(newData, this, false, false); + this.emit('createIcon', wall); + } + break; + } + this.selection.add(this.backgroundImage.getChildByName(newData.Id)); + }); + AxMessageSystem.send(CanvasAction.selectionChanged); + } } //////////////////////////////////////////////////////////////////////// 通用///////////////////////////////////////////////////////////////////////////// /** @@ -1357,7 +1362,7 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV public async onExamineeClickFloor() { await this.refreshBackgroundImage(); // 清空所有图形 - this.selection.deselectAll(); + this.deselectAll(); const itemList = []; this.backgroundImage.children.forEach(item => { if (item instanceof AxShape && item instanceof AxPreviewImageShape === false) { @@ -1384,7 +1389,7 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV public async onExaminerClickFloor() { await this.refreshBackgroundImage(); // 清空所有图形 - this.selection.deselectAll(); + this.deselectAll(); const itemList = []; this.backgroundImage.children.forEach(item => { if (item instanceof AxShape && item instanceof AxPreviewImageShape === false) { @@ -1410,7 +1415,7 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV public async onExaminerClickFloor_CreateTestpaper() { await this.refreshBackgroundImage(); // 清空所有图形 - this.selection.deselectAll(); + this.deselectAll(); const itemList = []; this.backgroundImage.children.forEach(item => { if (item instanceof AxShape && item instanceof AxPreviewImageShape === false) { @@ -1428,94 +1433,26 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV // 隐藏图标 this.setNameVisible(false, 0); } -} - -/** - * 选择器 - */ -export class Selection { - constructor(private workingArea: WorkingAreaComponent) {} - public objects: any[] = []; - public isMultiselection = false; - /** - * 返回选择器中是否包含对象 - * @param obj 对象 - */ - public contains(obj: any): boolean { - return this.objects.includes(obj); - } - /** - * 选定对象 - * @param obj 对象 - */ - public select(obj: any) { - if (!this.contains(obj)) { - this.workingArea.emit('select', obj); - this.objects.push(obj); - } - } - /** - * 取消选定对象 - * @param obj 对象 - */ - public deselect(obj: any) { - if (this.contains(obj)) { - this.workingArea.emit('deselect', obj); - const idx = this.objects.findIndex(x => x === obj); - this.objects.splice(idx, 1); - } - } - /** - * 选定或取消选定对象 - * @param obj 对象 - */ - public selectOrDeselect(obj: any) { - if (this.contains(obj)) { - this.deselect(obj); - } else { - this.select(obj); - } - } - /** - * 取消选定所有已选定对象 - */ + //////////////////////////////////////////////////////////////////// 选择逻辑 + // 取消所有选择 public deselectAll() { - this.objects.forEach(item => { - this.workingArea.emit('deselect', item); - }); - this.objects.splice(0, this.objects.length); - } - /** - * 取消选定所有对象后选定一个对象 - * @param obj 对象 - */ - public selectOne(obj: any) { - if (this.isMultiselection) { - this.selectOrDeselect(obj); - } else { - this.deselectAll(); - this.select(obj); + if (this.selection.first() !== null) { + this.selection.all().forEach(item => { + item.hideBorder(); + item.setPointVisiable(false); + }); + this.selection.clear(); + AxMessageSystem.send(CanvasAction.selectionChanged); } } - /** - * 选定对象集合中所有对象 - * @param objects 对象集合 - */ - public selectAll(objects: any[]) { - this.objects.forEach(item => { - this.select(item); - }); + // 选择单个 + public selectSingle(obj: any) { + this.deselectAll(); + this.selection.add(obj); + AxMessageSystem.send(CanvasAction.selectionChanged); } } - - -/** - * 车辆类型 - */ -export enum Type { - 水源 = 0, - 举高喷射消防车 = 1, - 泡沫消防车 = 2, - 水罐消防车 = 3, - 压缩空气泡沫消防车 = 4 +enum CanvasAction { + selectionChanged = 'selectionChanged', + copyDataChanged = 'copyDataChanged' } From e6c0c6c8b889935ee97c9df45dcb03fa2106acbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=8C=AF=E5=8D=87?= <359059686@qq.com> Date: Mon, 25 Jan 2021 09:11:03 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=88=A0=E9=99=A4debug.log?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- debug.log | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 debug.log diff --git a/debug.log b/debug.log deleted file mode 100644 index c4638ef..0000000 --- a/debug.log +++ /dev/null @@ -1,3 +0,0 @@ -[1229/141605.754:ERROR:directory_reader_win.cc(43)] FindFirstFile: ϵͳҲָ· (0x3) -[0104/100053.968:ERROR:directory_reader_win.cc(43)] FindFirstFile: ϵͳҲָ· (0x3) -[0122/085819.900:ERROR:directory_reader_win.cc(43)] FindFirstFile: ϵͳҲָ· (0x3) From 45ffea975865fcafe9fc7d1e378c1ef09ad64355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=8C=AF=E5=8D=87?= <359059686@qq.com> Date: Mon, 25 Jan 2021 11:47:35 +0800 Subject: [PATCH 3/3] 1.0.12.20210125b --- .gitignore | 1 + src/app/working-area/model/axSelection.ts | 4 + src/app/working-area/model/axShape.ts | 60 +++--- .../working-area/working-area.component.ts | 171 +++++++++++------- 4 files changed, 132 insertions(+), 104 deletions(-) diff --git a/.gitignore b/.gitignore index 86d943a..a80a6b3 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ testem.log # System Files .DS_Store Thumbs.db +debug.log diff --git a/src/app/working-area/model/axSelection.ts b/src/app/working-area/model/axSelection.ts index e61cd78..ce7a6e0 100644 --- a/src/app/working-area/model/axSelection.ts +++ b/src/app/working-area/model/axSelection.ts @@ -13,6 +13,10 @@ export class AxSelection { return null; } } + // 是否已经选择了对象 + public has(obj: any): boolean { + return this.objects.has(obj); + } // 获得所有对象 public all() { return this.objects; diff --git a/src/app/working-area/model/axShape.ts b/src/app/working-area/model/axShape.ts index 2d032d5..3a5dae7 100644 --- a/src/app/working-area/model/axShape.ts +++ b/src/app/working-area/model/axShape.ts @@ -20,6 +20,10 @@ export class AxShape extends Graphics { showName = true; // 边框 border: PIXI.Graphics = new PIXI.Graphics(); + // 鼠标位置 + mousePosition: PIXI.Point; + // 鼠标拖动 + mouseDragging: boolean; constructor(assetData: any, workingArea: WorkingAreaComponent) { super(); @@ -35,50 +39,30 @@ export class AxShape extends Graphics { .on('pointerdown', event => { event.stopPropagation(); if (this.selectable) { - this.workingArea.selectSingle(this); + this.workingArea.select(this); } if (this.moveable) { - event.currentTarget.data = event.data; - event.currentTarget.alpha = 0.5; - event.currentTarget.dragging = true; - - event.currentTarget.dragPoint = event.data.getLocalPosition(event.currentTarget.parent); - event.currentTarget.dragPoint.x -= event.currentTarget.x; - event.currentTarget.dragPoint.y -= event.currentTarget.y; + this.mouseDragging = true; + this.mousePosition = new PIXI.Point(event.data.global.x, event.data.global.y); } }) .on('pointerup', event => { - if (event.currentTarget.dragging) { - event.currentTarget.alpha = 1; - event.currentTarget.dragging = false; - event.currentTarget.data = null; - } + this.mouseDragging = false; }) .on('pointerupoutside', event => { - if (event.currentTarget.dragging) { - event.currentTarget.alpha = 1; - event.currentTarget.dragging = false; - event.currentTarget.data = null; - } + this.mouseDragging = false; }) .on('pointermove', event => { - if (event.currentTarget.dragging) { - const newPosition = event.currentTarget.data.getLocalPosition(event.currentTarget.parent); - - // const offsetX = newPosition.x - event.currentTarget.dragPoint.x; - // const offsetY = newPosition.y - event.currentTarget.dragPoint.y; - // const offset = this.workingArea.backgroundImage.toLocal(new Point(offsetX, offsetY)); - // event.currentTarget.position += offset; - // // this.workingArea.selection.objects.forEach(shpae => { - // // shpae.x = newPosition.x - event.currentTarget.dragPoint.x; - // // shpae.y = newPosition.y - event.currentTarget.dragPoint.y; - // // shpae.assetData.Point = new PIXI.Point(this.x, this.y); - // // this.workingArea.canvasData.isChange = true; - // // }) - event.currentTarget.x = newPosition.x - event.currentTarget.dragPoint.x; - event.currentTarget.y = newPosition.y - event.currentTarget.dragPoint.y; - this.assetData.Point = new PIXI.Point(this.x, this.y); - this.workingArea.canvasData.isChange = true; + if (this.mouseDragging) { + this.workingArea.selection.all().forEach(item => { + const x = event.data.global.x - this.mousePosition.x; + const y = event.data.global.y - this.mousePosition.y; + item.x += x * (1 / this.workingArea.backgroundImage.scale.x); + item.y += y * (1 / this.workingArea.backgroundImage.scale.y); + item.assetData.Point = new PIXI.Point(item.x, item.y); + this.workingArea.canvasData.isChange = true; + }); + this.mousePosition = new PIXI.Point(event.data.global.x, event.data.global.y); } }) .on('rightclick', event => { @@ -127,9 +111,9 @@ export class AxShape extends Graphics { this.border.lineStyle(scale * 1, 0x00a8ff); - let spaceLength = scale * 1; - let lineLenght = rect.width + 0.5 + 0.5; - let dashLength = scale * ( lineLenght + spaceLength - Math.floor((rect.width + rect.height) / 2 / 4.1)) / Math.floor((rect.width + rect.height) / 2 / 4.1); + const spaceLength = scale * 1; + const lineLenght = rect.width + 0.5 + 0.5; + const dashLength = scale * ( lineLenght + spaceLength - Math.floor((rect.width + rect.height) / 2 / 4.1)) / Math.floor((rect.width + rect.height) / 2 / 4.1); this.drawDash(this.border, p1.x - 0.5 * scale, p1.y, p2.x + 0.5 * scale, p2.y, dashLength, spaceLength); this.drawDash(this.border, p2.x, p2.y - 0.5 * scale, p3.x, p3.y + 0.5 * scale, dashLength, spaceLength); this.drawDash(this.border, p3.x + 0.5 * scale, p3.y, p4.x - 0.5 * scale, p4.y, dashLength, spaceLength); diff --git a/src/app/working-area/working-area.component.ts b/src/app/working-area/working-area.component.ts index 1b05d4c..851b75d 100644 --- a/src/app/working-area/working-area.component.ts +++ b/src/app/working-area/working-area.component.ts @@ -151,7 +151,7 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV * RC版: 该版本已经相当成熟了,基本上不存在导致错误的BUG,与即将发行的正式版相差无几。 * Release版: 该版本意味“最终版本”,在前面版本的一系列测试版之后,终归会有一个正式版本,是最终交付用户使用的一个版本。该版本有时也称为标准版。一般情况下,Release不会以单词形式出现在软件封面上,取而代之的是符号®。 */ - public VERSION = '1.0.11.20210122_beta'; + public VERSION = '1.0.12.20210125_beta'; /** * 数据初始化 */ @@ -174,14 +174,6 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV this.deleteSelectedShape(); } }); - // 消息系统事件监听 - AxMessageSystem.addListener(CanvasAction.selectionChanged, () => { - this.selection.all().forEach(item => { - item.showBorder(); - item.drawBorder(1 / this.backgroundImage.scale.x); - item.setPointVisiable(this.allowEdit); - }); - }, this); } /** * 删除选中的图标 @@ -391,28 +383,6 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV this.rectToolGraphics.endFill(); } }); - /** - * 选中事件 - */ - this.on('select', (axShape: AxShape) => { - // if (axShape instanceof AxRectangleShape) { - // let upLeft: PIXI.Sprite= new PIXI.Sprite(this.editorPointTexture); - // let upRight: PIXI.Sprite= new PIXI.Sprite(this.editorPointTexture); - // let downLeft: PIXI.Sprite= new PIXI.Sprite(this.editorPointTexture); - // let downRight: PIXI.Sprite = new PIXI.Sprite(this.editorPointTexture); - // } else { - axShape.showBorder(); - axShape.drawBorder(1 / this.backgroundImage.scale.x); - axShape.setPointVisiable(this.allowEdit); - // } - }); - /** - * 取消选中事件 - */ - this.on('deselect', (axShape: AxShape) => { - axShape.hideBorder(); - axShape.setPointVisiable(false); - }); /** * 创建图标事件(数据处理) */ @@ -451,12 +421,6 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV this.emit('canvasDataChanged'); this.canvasData.isChange = true; }); - /** - * 删除图标事件(数据处理) - */ - this.on('deleteIcon', (axShape: AxShape) => { - - }); } /** * 重置画布 @@ -517,18 +481,6 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV } }); } - /** - * 设置选中 - * 清空所有选择对象,选择ids集合元素 - */ - public setHighlight(ids: string[]): void { - this.selection.clear(); - ids.forEach(item => { - const obj = this.backgroundImage.getChildByName(item); - this.selection.add(obj); - }); - AxMessageSystem.send(''); - } /** * 创建楼层图形 */ @@ -842,22 +794,21 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV event.currentTarget.data = null; if (this.rectToolGraphics.visible === true) { + const shapes: AxShape[] = []; this.backgroundImage.children.forEach(item => { - if ( item instanceof AxImageShape - || item instanceof MultipointIcon - || item instanceof PolygonIcon - || item instanceof AxArrowConnector) { + if ( item instanceof AxShape + && item instanceof AxPreviewImageShape === false) { // 判断2个矩形是否相交 const rect1 = this.rectToolGraphics.getBounds(); const rect2 = item.getBounds(); if (this.isOverlap(rect1, rect2)) { - this.selection.add(item); + shapes.push(item); } } }); this.rectToolGraphics.clear(); this.rectToolGraphics.visible = false; - AxMessageSystem.send(CanvasAction.selectionChanged); + this.selectAll(shapes); } }) .on('pointerupoutside', event => { @@ -1303,12 +1254,13 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV * 粘贴 */ public paste(companyId: string, buildingId: string, floorId: string): void { + const ids: string[] = []; if (this.copyData.length > 0) { this.copyData.forEach(item => { item.Point = new PIXI.Point(item.Point.x + 5, item.Point.y + 5); const newData = JSON.parse(JSON.stringify(item)); newData.Id = ObjectID.default.generate(), - newData.CompanyId = companyId; + newData.CompanyId = companyId; newData.BuildingId = buildingId; newData.FloorId = floorId; newData.Point = new PIXI.Point(item.Point.x + 5, item.Point.y + 5); @@ -1335,9 +1287,9 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV } break; } - this.selection.add(this.backgroundImage.getChildByName(newData.Id)); + ids.push(newData.Id); }); - AxMessageSystem.send(CanvasAction.selectionChanged); + this.setHighlight(ids); } } //////////////////////////////////////////////////////////////////////// 通用///////////////////////////////////////////////////////////////////////////// @@ -1434,22 +1386,109 @@ export class WorkingAreaComponent extends EventEmitter implements OnInit, AfterV this.setNameVisible(false, 0); } //////////////////////////////////////////////////////////////////// 选择逻辑 - // 取消所有选择 + /** + * 清空选择,选择单个形状 + * @param shape 形状 + */ + public selectSingle(shape: AxShape) { + if (this.selection.first() !== null) { + this.selection.all().forEach(item => { + this.clearSelectEffect(item); + }); + this.selection.clear(); + } + this.selection.add(shape); + this.setSelectEffect(shape); + AxMessageSystem.send(CanvasAction.selectionChanged); + } + /** + * 选择 + * @param shape 形状 + */ + public select(shape: AxShape) { + if (this.selection.first() !== null + && !this.isCtrlKeyClicked + && !this.selection.has(shape)) { + this.selection.all().forEach(item => { + this.clearSelectEffect(item); + }); + this.selection.clear(); + } + this.selection.add(shape); + this.setSelectEffect(shape); + AxMessageSystem.send(CanvasAction.selectionChanged); + } + /** + * 选择集合中的形状 + * @param shape 形状集合 + */ + public selectAll(shape: AxShape[]) { + this.selection.addArray(shape); + this.selection.all().forEach(item => { + this.setSelectEffect(item); + }); + AxMessageSystem.send(CanvasAction.selectionChanged); + } + /** + * 先清空再选择全部 + * @param shape 形状集合 + */ + public selectAllWithClear(shape: AxShape[]) { + if (this.selection.first() !== null) { + this.selection.all().forEach(item => { + this.clearSelectEffect(item); + }); + this.selection.clear(); + } + this.selection.addArray(shape); + this.selection.all().forEach(item => { + this.setSelectEffect(item); + }); + AxMessageSystem.send(CanvasAction.selectionChanged); + } + /** + * 选择集合中所有id的形状 + * @param ids 形状id集合 + */ + public setHighlight(ids: string[]): void { + const shapes: AxShape[] = []; + // 重新选择 + ids.forEach(item => { + const obj = this.backgroundImage.getChildByName(item); + shapes.push(obj as AxShape); + }); + this.selectAllWithClear(shapes); + } + /** + * 取消所有选择 + */ public deselectAll() { if (this.selection.first() !== null) { this.selection.all().forEach(item => { - item.hideBorder(); - item.setPointVisiable(false); + this.clearSelectEffect(item); }); this.selection.clear(); AxMessageSystem.send(CanvasAction.selectionChanged); } } - // 选择单个 - public selectSingle(obj: any) { - this.deselectAll(); - this.selection.add(obj); - AxMessageSystem.send(CanvasAction.selectionChanged); + /** + * 设置选中效果 + * @param shape 形状 + */ + public setSelectEffect(shape: AxShape) { + shape.hideBorder(); + shape.setPointVisiable(false); + shape.showBorder(); + shape.drawBorder(1 / this.backgroundImage.scale.x); + shape.setPointVisiable(this.allowEdit); + } + /** + * 设置形状选中效果 + * @param shape 形状 + */ + public clearSelectEffect(shape: AxShape) { + shape.hideBorder(); + shape.setPointVisiable(false); } } enum CanvasAction {