From 569c4d84380379bcb59eae41fee24ea307261872 Mon Sep 17 00:00:00 2001 From: fan Date: Wed, 26 Jul 2023 17:47:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=B4=A7=E6=80=A5=E5=85=B3?= =?UTF-8?q?=E9=97=AD=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/draw-app/DrawProperties.vue | 5 + .../draw-app/properties/EsbButtonProperty.vue | 51 ++++++++ .../draw-app/properties/GatedBoxProperty.vue | 6 + src/drawApp/graphics/EsbButtonInteraction.ts | 103 +++++++++++++++ src/drawApp/graphics/GatedBoxInteraction.ts | 2 +- src/drawApp/index.ts | 15 +++ src/graphics/esbButton/EsbButton.ts | 100 +++++++++++++++ .../esbButton/EsbButtonDrawAssistant.ts | 120 ++++++++++++++++++ src/graphics/gatedBox/GatedBox.ts | 2 +- src/graphics/spksSwitch/SpksSwitch.ts | 2 +- 10 files changed, 403 insertions(+), 3 deletions(-) create mode 100644 src/components/draw-app/properties/EsbButtonProperty.vue create mode 100644 src/drawApp/graphics/EsbButtonInteraction.ts create mode 100644 src/graphics/esbButton/EsbButton.ts create mode 100644 src/graphics/esbButton/EsbButtonDrawAssistant.ts diff --git a/src/components/draw-app/DrawProperties.vue b/src/components/draw-app/DrawProperties.vue index 7101d9b..96b1ec7 100644 --- a/src/components/draw-app/DrawProperties.vue +++ b/src/components/draw-app/DrawProperties.vue @@ -90,6 +90,9 @@ + @@ -133,6 +136,8 @@ import SpksSwitchProperty from './properties/SpksSwitchProperty.vue'; import { SpksSwitch } from 'src/graphics/spksSwitch/SpksSwitch'; import GatedBoxProperty from './properties/GatedBoxProperty.vue'; import { GatedBox } from 'src/graphics/gatedBox/GatedBox'; +import EsbButtonProperty from './properties/EsbButtonProperty.vue'; +import { EsbButton } from 'src/graphics/esbButton/EsbButton'; const drawStore = useDrawStore(); diff --git a/src/components/draw-app/properties/EsbButtonProperty.vue b/src/components/draw-app/properties/EsbButtonProperty.vue new file mode 100644 index 0000000..1e12a74 --- /dev/null +++ b/src/components/draw-app/properties/EsbButtonProperty.vue @@ -0,0 +1,51 @@ + + + diff --git a/src/components/draw-app/properties/GatedBoxProperty.vue b/src/components/draw-app/properties/GatedBoxProperty.vue index 169cdf4..04208b9 100644 --- a/src/components/draw-app/properties/GatedBoxProperty.vue +++ b/src/components/draw-app/properties/GatedBoxProperty.vue @@ -8,6 +8,12 @@ @blur="onUpdate" label="索引" /> + diff --git a/src/drawApp/graphics/EsbButtonInteraction.ts b/src/drawApp/graphics/EsbButtonInteraction.ts new file mode 100644 index 0000000..c2e2936 --- /dev/null +++ b/src/drawApp/graphics/EsbButtonInteraction.ts @@ -0,0 +1,103 @@ +import * as pb_1 from 'google-protobuf'; +import { DisplayObject, FederatedMouseEvent } from 'pixi.js'; +import { EsbButton, IEsbButton } from 'src/graphics/esbButton/EsbButton'; +import { + GraphicApp, + GraphicInteractionPlugin, + JlGraphic, +} from 'src/jl-graphic'; +import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu'; +import { MenuItemOptions } from 'src/jl-graphic/ui/Menu'; + +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase } from './GraphicDataBase'; + +export class EsbButtonData extends GraphicDataBase implements IEsbButton { + constructor(data?: graphicData.EsbButton) { + let esbButton; + if (!data) { + esbButton = new graphicData.EsbButton({ + common: GraphicDataBase.defaultCommonInfo(EsbButton.Type), + }); + } else { + esbButton = data; + } + super(esbButton); + } + + public get data(): graphicData.EsbButton { + return this.getData(); + } + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get flip(): boolean { + return this.data.flip; + } + set flip(v: boolean) { + this.data.flip = v; + } + get index(): number { + return this.data.index; + } + set index(v: number) { + this.data.index = v; + } + clone(): EsbButtonData { + return new EsbButtonData(this.data.cloneMessage()); + } + copyFrom(data: EsbButtonData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: EsbButtonData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} + +const flipConfig: MenuItemOptions = { + name: '上下翻转', +}; +const EsbButtonEditMenu: ContextMenu = ContextMenu.init({ + name: '紧急关闭按钮编辑菜单', + groups: [ + { + items: [flipConfig], + }, + ], +}); +export class DrawEsbButtonInteraction extends GraphicInteractionPlugin { + static Name = 'esb_button_draw_right_menu'; + constructor(app: GraphicApp) { + super(DrawEsbButtonInteraction.Name, app); + app.registerMenu(EsbButtonEditMenu); + } + static init(app: GraphicApp) { + return new DrawEsbButtonInteraction(app); + } + filter(...grahpics: JlGraphic[]): EsbButton[] | undefined { + return grahpics + .filter((g) => g.type === EsbButton.Type) + .map((g) => g as EsbButton); + } + bind(g: EsbButton): void { + g.on('_rightclick', this.onContextMenu, this); + } + + unbind(g: EsbButton): void { + g.off('_rightclick', this.onContextMenu, this); + } + + onContextMenu(e: FederatedMouseEvent) { + const target = e.target as DisplayObject; + const esbButton = target.getGraphic() as EsbButton; + this.app.updateSelected(esbButton); + flipConfig.handler = () => { + esbButton.datas.flip = !esbButton.datas.flip; + esbButton.repaint(); + }; + EsbButtonEditMenu.open(e.global); + } +} diff --git a/src/drawApp/graphics/GatedBoxInteraction.ts b/src/drawApp/graphics/GatedBoxInteraction.ts index 5595f5e..ecf2f6f 100644 --- a/src/drawApp/graphics/GatedBoxInteraction.ts +++ b/src/drawApp/graphics/GatedBoxInteraction.ts @@ -61,7 +61,7 @@ const flipConfig: MenuItemOptions = { name: '上下翻转', }; const GatedBoxEditMenu: ContextMenu = ContextMenu.init({ - name: 'Spks开关编辑菜单', + name: '门控箱编辑菜单', groups: [ { items: [flipConfig], diff --git a/src/drawApp/index.ts b/src/drawApp/index.ts index bf7a2f2..14f5799 100644 --- a/src/drawApp/index.ts +++ b/src/drawApp/index.ts @@ -95,10 +95,16 @@ import { GatedBoxData, DrawGatedBoxInteraction, } from './graphics/GatedBoxInteraction'; +import { EsbButton, EsbButtonTemplate } from 'src/graphics/esbButton/EsbButton'; +import { + EsbButtonData, + DrawEsbButtonInteraction, +} from './graphics/EsbButtonInteraction'; import { Notify, Dialog } from 'quasar'; import { checkMapData } from 'src/api/Simulation'; import { SpksSwitchDraw } from 'src/graphics/spksSwitch/SpksSwitchDrawAssistant'; import { GatedBoxDraw } from 'src/graphics/gatedBox/GatedBoxDrawAssistant'; +import { EsbButtonDraw } from 'src/graphics/esbButton/EsbButtonDrawAssistant'; // export function fromStoragePoint(p: graphicData.Point): Point { // return new Point(p.x, p.y); @@ -234,6 +240,7 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp { | StopPositionDraw | SpksSwitchDraw | GatedBoxDraw + | EsbButtonDraw )[] = []; if (draftType === 'Line') { drawAssistants = [ @@ -277,11 +284,13 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp { ), new SpksSwitchDraw(app, new SpksSwitchTemplate(new SpksSwitchData())), new GatedBoxDraw(app, new GatedBoxTemplate(new GatedBoxData())), + new EsbButtonDraw(app, new EsbButtonTemplate(new EsbButtonData())), ]; DrawSignalInteraction.init(app); DrawStopPositionInteraction.init(app); DrawSpksSwitchInteraction.init(app); DrawGatedBoxInteraction.init(app); + DrawEsbButtonInteraction.init(app); } const isSupportDeletion = (g: JlGraphic) => { if (g.type === LogicSection.Type && g.selected) { @@ -482,6 +491,9 @@ export function saveDrawDatas(app: JlDrawApp) { } else if (GatedBox.Type === g.type) { const gatedBoxData = (g as GatedBox).saveData(); storage.gateBoxs.push((gatedBoxData as GatedBoxData).data); + } else if (EsbButton.Type === g.type) { + const esbButtonData = (g as EsbButton).saveData(); + storage.esbButtons.push((esbButtonData as EsbButtonData).data); } }); const base64 = fromUint8Array(storage.serialize()); @@ -559,6 +571,9 @@ export async function loadDrawDatas(app: GraphicApp) { storage.gateBoxs.forEach((gatedBox) => { datas.push(new GatedBoxData(gatedBox)); }); + storage.esbButtons.forEach((esbButton) => { + datas.push(new EsbButtonData(esbButton)); + }); await app.loadGraphic(datas); } else { app.loadGraphic([]); diff --git a/src/graphics/esbButton/EsbButton.ts b/src/graphics/esbButton/EsbButton.ts new file mode 100644 index 0000000..f282066 --- /dev/null +++ b/src/graphics/esbButton/EsbButton.ts @@ -0,0 +1,100 @@ +import { Graphics } from 'pixi.js'; +import { + GraphicData, + JlGraphic, + JlGraphicTemplate, + VectorText, +} from 'src/jl-graphic'; + +export interface IEsbButton extends GraphicData { + get code(): string; + set code(v: string); + get flip(): boolean; + set flip(v: boolean); + get index(): number; + set index(v: number); + clone(): IEsbButton; + copyFrom(data: IEsbButton): void; + eq(other: IEsbButton): boolean; +} + +const esbButtonConsts = { + codeFontSize: 12, + codeColor: 0xffffff, + bodyLineColor: 0xffffff, + bodyLineWidth: 4, + bodyRectLineColor: 0xffffff, + bodyRectLineWidth: 2, + bodyRectWidth: 20, + bodyRectHeight: 20, + bodyCircleRadius: 5, + bodyCircleColor: 0xffffff, + bodyColor: 0x000000, +}; +export class EsbButton extends JlGraphic { + static Type = 'esbButton'; + codeGraph: VectorText = new VectorText(''); + circleBody: Graphics = new Graphics(); + rectBody: Graphics = new Graphics(); + lineBody: Graphics = new Graphics(); + + constructor() { + super(EsbButton.Type); + this.addChild(this.codeGraph); + this.addChild(this.rectBody); + this.addChild(this.lineBody); + this.addChild(this.circleBody); + } + get datas(): IEsbButton { + return this.getDatas(); + } + get code(): string { + return this.datas.index + ''; + } + doRepaint(): void { + const codeGraph = this.codeGraph; + codeGraph.text = this.datas.code; + codeGraph.style.fill = esbButtonConsts.codeColor; + codeGraph.setVectorFontSize(esbButtonConsts.codeFontSize); + codeGraph.anchor.set(0.5); + codeGraph.position.set(-30, 0); + this.circleBody.clear(); + this.circleBody.beginFill(esbButtonConsts.bodyCircleColor, 1); + this.circleBody.drawCircle(0, 0, esbButtonConsts.bodyCircleRadius); + this.circleBody.endFill(); + this.rectBody.clear(); + this.rectBody.beginFill(esbButtonConsts.bodyColor, 0); + this.rectBody.lineStyle( + esbButtonConsts.bodyRectLineWidth, + esbButtonConsts.bodyRectLineColor + ); + this.rectBody.drawRect( + -esbButtonConsts.bodyRectWidth / 2, + -esbButtonConsts.bodyRectHeight / 2, + esbButtonConsts.bodyRectWidth, + esbButtonConsts.bodyRectHeight + ); + this.rectBody.endFill(); + this.lineBody.clear(); + const lineY = this.datas.flip + ? esbButtonConsts.bodyRectHeight / 2 + : -esbButtonConsts.bodyRectHeight / 2; + this.lineBody.lineStyle( + esbButtonConsts.bodyLineWidth, + esbButtonConsts.bodyLineColor + ); + this.lineBody.moveTo(-esbButtonConsts.bodyRectWidth / 2, lineY); + this.lineBody.lineTo(esbButtonConsts.bodyRectWidth / 2, lineY); + } +} + +export class EsbButtonTemplate extends JlGraphicTemplate { + constructor(dataTemplate: IEsbButton) { + super(EsbButton.Type, { dataTemplate }); + } + new(): EsbButton { + const esbButton = new EsbButton(); + esbButton.loadData(this.datas); + return esbButton; + } +} diff --git a/src/graphics/esbButton/EsbButtonDrawAssistant.ts b/src/graphics/esbButton/EsbButtonDrawAssistant.ts new file mode 100644 index 0000000..3becadf --- /dev/null +++ b/src/graphics/esbButton/EsbButtonDrawAssistant.ts @@ -0,0 +1,120 @@ +import { DisplayObject, FederatedMouseEvent, Point } from 'pixi.js'; +import { + AbsorbableLine, + AbsorbablePosition, + GraphicDrawAssistant, + GraphicInteractionPlugin, + GraphicTransformEvent, + JlDrawApp, + JlGraphic, +} from 'src/jl-graphic'; +import { EsbButton, EsbButtonTemplate, IEsbButton } from './EsbButton'; + +export interface IEsbButtonDrawOptions { + newData: () => IEsbButton; +} +export class EsbButtonDraw extends GraphicDrawAssistant< + EsbButtonTemplate, + IEsbButton +> { + _esbButton: EsbButton | null = null; + constructor(app: JlDrawApp, template: EsbButtonTemplate) { + super( + app, + template, + 'svguse:../../drawIcon.svg#icon-esb-button', + '紧急关闭按钮EsbButton' + ); + EsbButtonInteraction.init(app); + } + public get esbButton(): EsbButton { + if (!this._esbButton) { + this._esbButton = this.graphicTemplate.new(); + this._esbButton.loadData(this.graphicTemplate.datas); + this.container.addChild(this._esbButton); + } + return this._esbButton; + } + + onRightClick(): void { + this.createAndStore(true); + } + + onLeftUp(e: FederatedMouseEvent): void { + this.container.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(true); + } + + redraw(p: Point): void { + this.esbButton.repaint(); + this.container.position.set(p.x, p.y); + } + + prepareData(data: IEsbButton): boolean { + data.transform = this.container.saveTransform(); + data.code = 'ESB'; + return true; + } +} +/** + * 构建吸附线 + * @param esbButton + */ +function buildAbsorbablePositions(esbButton: EsbButton): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const esbButtons = esbButton.queryStore.queryByType( + EsbButton.Type + ); + const canvas = esbButton.getCanvas(); + esbButtons.forEach((item) => { + if (item.id === esbButton.id) { + return; + } + const ala = new AbsorbableLine( + new Point(item.x, 0), + new Point(item.x, canvas.height) + ); + const alb = new AbsorbableLine( + new Point(0, item.y), + new Point(canvas.width, item.y) + ); + aps.push(ala); + aps.push(alb); + }); + return aps; +} + +export class EsbButtonInteraction extends GraphicInteractionPlugin { + static Name = 'esb_button_transform'; + constructor(app: JlDrawApp) { + super(EsbButtonInteraction.Name, app); + } + static init(app: JlDrawApp) { + return new EsbButtonInteraction(app); + } + filter(...grahpics: JlGraphic[]): EsbButton[] | undefined { + return grahpics + .filter((g) => g.type === EsbButton.Type) + .map((g) => g as EsbButton); + } + bind(g: EsbButton): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + g.on('transformstart', this.transformstart, this); + } + unbind(g: EsbButton): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + g.off('transformstart', this.transformstart, this); + } + transformstart(e: GraphicTransformEvent) { + const target = e.target as DisplayObject; + const esbButotn = target.getGraphic() as EsbButton; + esbButotn.getGraphicApp().setOptions({ + absorbablePositions: buildAbsorbablePositions(esbButotn), + }); + } +} diff --git a/src/graphics/gatedBox/GatedBox.ts b/src/graphics/gatedBox/GatedBox.ts index 85279ae..e6dde4e 100644 --- a/src/graphics/gatedBox/GatedBox.ts +++ b/src/graphics/gatedBox/GatedBox.ts @@ -31,7 +31,7 @@ const gatedBoxConsts = { }; export class GatedBox extends JlGraphic { static Type = 'gatedBox'; - codeGraph: VectorText = new VectorText(''); // 编组数量 + codeGraph: VectorText = new VectorText(''); rectBody: Graphics = new Graphics(); lineBody: Graphics = new Graphics(); diff --git a/src/graphics/spksSwitch/SpksSwitch.ts b/src/graphics/spksSwitch/SpksSwitch.ts index ba4822a..ccb86e5 100644 --- a/src/graphics/spksSwitch/SpksSwitch.ts +++ b/src/graphics/spksSwitch/SpksSwitch.ts @@ -31,7 +31,7 @@ const spksSwitchConsts = { }; export class SpksSwitch extends JlGraphic { static Type = 'spksSwitch'; - codeGraph: VectorText = new VectorText(''); // 编组数量 + codeGraph: VectorText = new VectorText(''); rectBody: Graphics = new Graphics(); lineBody: Graphics = new Graphics();