diff --git a/graphic-pixi b/graphic-pixi index 0338431..3fe8f89 160000 --- a/graphic-pixi +++ b/graphic-pixi @@ -1 +1 @@ -Subproject commit 033843126732ca06a4e0c4a4beac72f074dead8a +Subproject commit 3fe8f895fa2458f7e7b93f24558fdc81a11c3f13 diff --git a/public/drawIcon.svg b/public/drawIcon.svg index 2435e9b..b11ecad 100644 --- a/public/drawIcon.svg +++ b/public/drawIcon.svg @@ -54,4 +54,11 @@ + + + + + + + diff --git a/src/drawApp/commonApp.ts b/src/drawApp/commonApp.ts index a81022f..09e1881 100644 --- a/src/drawApp/commonApp.ts +++ b/src/drawApp/commonApp.ts @@ -73,15 +73,15 @@ import { GatedBoxData, DrawGatedBoxInteraction, } from './graphics/GatedBoxInteraction'; -import { EsbButton, EsbButtonTemplate } from 'src/graphics/esbButton/EsbButton'; -import { - EsbButtonData, - DrawEsbButtonInteraction, - EsbButtonState, -} from './graphics/EsbButtonInteraction'; +// import { EsbButton, EsbButtonTemplate } from 'src/graphics/esbButton/EsbButton'; +// import { +// EsbButtonData, +// DrawEsbButtonInteraction, +// EsbButtonState, +// } from './graphics/EsbButtonInteraction'; import { SpksSwitchDraw } from 'src/graphics/spksSwitch/SpksSwitchDrawAssistant'; import { GatedBoxDraw } from 'src/graphics/gatedBox/GatedBoxDrawAssistant'; -import { EsbButtonDraw } from 'src/graphics/esbButton/EsbButtonDrawAssistant'; +// import { EsbButtonDraw } from 'src/graphics/esbButton/EsbButtonDrawAssistant'; import { TransponderDraw } from 'src/graphics/transponder/TransponderDrawAssistant'; import { Transponder, @@ -175,10 +175,10 @@ export function initCommonDrawApp(app: IDrawApp) { new StopPositionDraw(app, new StopPositionTemplate(new StopPositionData())); new SpksSwitchDraw(app, new SpksSwitchTemplate(new SpksSwitchData())); new GatedBoxDraw(app, new GatedBoxTemplate(new GatedBoxData())); - new EsbButtonDraw( - app, - new EsbButtonTemplate(new EsbButtonData(), new EsbButtonState()) - ); + // new EsbButtonDraw( + // app, + // new EsbButtonTemplate(new EsbButtonData(), new EsbButtonState()) + // ); new SlopeKiloMarkerDrawAssistant( app, new SlopeKiloMarkerTemplate(new SlopeKiloMarkerData()) @@ -194,7 +194,7 @@ export function initCommonDrawApp(app: IDrawApp) { DrawStopPositionInteraction.init(app); DrawSpksSwitchInteraction.init(app); DrawGatedBoxInteraction.init(app); - DrawEsbButtonInteraction.init(app); + // DrawEsbButtonInteraction.init(app); // 画布右键菜单 app.registerMenu(DefaultCanvasMenu); @@ -270,9 +270,9 @@ export function loadCommonDrawDatas( storage.gateBoxs.forEach((gatedBox) => { datas.push(new GatedBoxData(gatedBox)); }); - storage.esbButtons.forEach((esbButton) => { - datas.push(new EsbButtonData(esbButton)); - }); + // storage.esbButtons.forEach((esbButton) => { + // datas.push(new EsbButtonData(esbButton)); + // }); storage.transponders.forEach((transponder) => { datas.push(new TransponderData(transponder)); }); @@ -339,9 +339,9 @@ export function saveCommonDrawDatas( } 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); + // } else if (EsbButton.Type === g.type) { + // const esbButtonData = (g as EsbButton).saveData(); + // storage.esbButtons.push((esbButtonData as EsbButtonData).data); } else if (Transponder.Type === g.type) { const transponderData = (g as Transponder).saveData(); storage.transponders.push((transponderData as TransponderData).data); diff --git a/src/drawApp/graphics/ZdwxEsbInteraction.ts b/src/drawApp/graphics/ZdwxEsbInteraction.ts new file mode 100644 index 0000000..d64d37d --- /dev/null +++ b/src/drawApp/graphics/ZdwxEsbInteraction.ts @@ -0,0 +1,190 @@ +import * as pb_1 from 'google-protobuf'; +import { DisplayObject, FederatedMouseEvent } from 'pixi.js'; +import { + ZdwxEsb, + IZdwxEsbData, + IZdwxEsbState, +} from 'src/graphics/esbButton/ZdwxEsb'; +import { + IGraphicApp, + GraphicInteractionPlugin, + JlGraphic, + IGraphicScene, +} 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, GraphicStateBase } from './GraphicDataBase'; +import { useLineStore } from 'src/stores/line-store'; +import { state } from 'src/protos/device_state'; + +export class ZdwxEsbData extends GraphicDataBase implements IZdwxEsbData { + constructor(data?: graphicData.EsbButton) { + let esbButton; + if (!data) { + esbButton = new graphicData.EsbButton({ + common: GraphicDataBase.defaultCommonInfo(ZdwxEsb.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; + } + get refStand(): string { + return this.data.refStand; + } + set refStand(v: string) { + this.data.refStand = v; + } + clone(): ZdwxEsbData { + return new ZdwxEsbData(this.data.cloneMessage()); + } + copyFrom(data: ZdwxEsbData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: ZdwxEsbData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} + +export class ZdwxEsbState extends GraphicStateBase implements IZdwxEsbState { + constructor(data?: state.ButtonState) { + let ibpButtonState; + if (data) { + ibpButtonState = data; + } else { + ibpButtonState = new state.ButtonState(); + } + super(ibpButtonState, ZdwxEsb.Type); + } + get states(): state.ButtonState { + return this.getState(); + } + get code(): string { + return this.states.id; + } + get id(): string { + return this.states.id; + } + set id(v: string) { + this.states.id = v; + } + get down(): boolean { + return this.states.down; + } + set down(v: boolean) { + this.states.down = v; + } + clone(): ZdwxEsbState { + return new ZdwxEsbState(this.states.cloneMessage()); + } + copyFrom(data: GraphicStateBase): void { + pb_1.Message.copyInto(data._state, this._state); + } + eq(data: GraphicStateBase): boolean { + return pb_1.Message.equals(this._state, data._state); + } +} + +const flipConfig: MenuItemOptions = { + name: '上下翻转', +}; +const EsbButtonEditMenu: ContextMenu = ContextMenu.init({ + name: '紧急关闭按钮编辑菜单', + groups: [ + { + items: [flipConfig], + }, + ], +}); +export class DrawZdwxEsbInteraction extends GraphicInteractionPlugin { + static Name = 'zdwx_esb_draw_right_menu'; + constructor(app: IGraphicApp) { + super(DrawZdwxEsbInteraction.Name, app); + app.registerMenu(EsbButtonEditMenu); + } + static init(app: IGraphicApp) { + return new DrawZdwxEsbInteraction(app); + } + filter(...grahpics: JlGraphic[]): ZdwxEsb[] | undefined { + return grahpics + .filter((g) => g.type === ZdwxEsb.Type) + .map((g) => g as ZdwxEsb); + } + bind(g: ZdwxEsb): void { + g.on('_rightclick', this.onContextMenu, this); + } + + unbind(g: ZdwxEsb): void { + g.off('_rightclick', this.onContextMenu, this); + } + + onContextMenu(e: FederatedMouseEvent) { + const target = e.target as DisplayObject; + const esbButton = target.getGraphic() as ZdwxEsb; + this.app.updateSelected(esbButton); + flipConfig.handler = () => { + esbButton.datas.flip = !esbButton.datas.flip; + esbButton.repaint(); + }; + EsbButtonEditMenu.open(e.global); + } +} + +export class ZdwxEsbOperationInteraction extends GraphicInteractionPlugin { + static Name = 'zdwx_esb_operation'; + constructor(scene: IGraphicScene) { + super(ZdwxEsbOperationInteraction.Name, scene); + } + static init(scene: IGraphicScene) { + return new ZdwxEsbOperationInteraction(scene); + } + filter(...grahpics: JlGraphic[]): ZdwxEsb[] | undefined { + return grahpics.filter((g): g is ZdwxEsb => g.type === ZdwxEsb.Type); + } + bind(g: ZdwxEsb): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.on('mousedown', this.onPress, this); + } + unbind(g: ZdwxEsb): void { + g.eventMode = 'none'; + g.cursor = 'default'; + g.off('mousedown', this.onPress, this); + } + onPress(e: FederatedMouseEvent) { + const g = e.target as ZdwxEsb; + g.on('mouseleave', this.onRelease, this); + g.on('mouseup', this.onRelease, this); + useLineStore().esbButtonOperation(true, g.datas.id); + } + onRelease(e: FederatedMouseEvent) { + const g = e.target as ZdwxEsb; + g.off('mouseleave', this.onRelease, this); + g.off('mouseup', this.onRelease, this); + useLineStore().esbButtonOperation(false, g.datas.id); + } +} diff --git a/src/drawApp/jkApp.ts b/src/drawApp/jkApp.ts index a5b420a..d5b4041 100644 --- a/src/drawApp/jkApp.ts +++ b/src/drawApp/jkApp.ts @@ -45,6 +45,9 @@ import { SignalTemplate, Signal } from 'src/graphics/signal/Signal'; import { SignalData, SignalState } from './graphics/SignalInteraction'; import { getCategoryConsts } from './gategoryConsts'; import { CategoryType } from 'src/components/CategoryType'; +import { EsbButtonDraw } from 'src/graphics/esbButton/EsbButtonDrawAssistant'; +import { EsbButton, EsbButtonTemplate } from 'src/graphics/esbButton/EsbButton'; +import { EsbButtonData, EsbButtonState } from './graphics/EsbButtonInteraction'; let jkDrawApp: IDrawApp | null = null; @@ -118,6 +121,10 @@ export function initJkDrawApp(): IDrawApp { app, new AxleCountingSectionTemplate(new AxleCountingSectionData()) ); + new EsbButtonDraw( + app, + new EsbButtonTemplate(new EsbButtonData(), new EsbButtonState()) + ); new LogicSectionDraw(app, new LogicSectionTemplate(new LogicSectionData())); app.addKeyboardListener( new KeyListener({ @@ -156,6 +163,9 @@ export async function loadJkDrawDatas(): Promise { storage.logicSections.forEach((logicSection) => { datas.push(new LogicSectionData(logicSection)); }); + storage.esbButtons.forEach((esbButton) => { + datas.push(new EsbButtonData(esbButton)); + }); return Promise.resolve({ canvasProperty: storage.canvas, datas: datas, @@ -183,6 +193,9 @@ export function saveJkDrawDatas(app: IDrawApp) { } else if (LogicSection.Type === g.type) { const logicSectionData = (g as LogicSection).saveData(); storage.logicSections.push((logicSectionData as LogicSectionData).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()); diff --git a/src/drawApp/thApp.ts b/src/drawApp/thApp.ts index 6449d22..54a2da6 100644 --- a/src/drawApp/thApp.ts +++ b/src/drawApp/thApp.ts @@ -34,6 +34,9 @@ import { SignalTemplate, Signal } from 'src/graphics/signal/Signal'; import { SignalData, SignalState } from './graphics/SignalInteraction'; import { getCategoryConsts } from './gategoryConsts'; import { CategoryType } from 'src/components/CategoryType'; +import { EsbButtonDraw } from 'src/graphics/esbButton/EsbButtonDrawAssistant'; +import { EsbButton, EsbButtonTemplate } from 'src/graphics/esbButton/EsbButton'; +import { EsbButtonData, EsbButtonState } from './graphics/EsbButtonInteraction'; let thDrawApp: IDrawApp | null = null; @@ -89,6 +92,10 @@ export function initThDrawApp(): IDrawApp { getThTypeConsts(Signal.Type) ) ); + new EsbButtonDraw( + app, + new EsbButtonTemplate(new EsbButtonData(), new EsbButtonState()) + ); new TrackSectionDraw(app, new TrackSectionTemplate(new TrackSectionData())); new TrackLogicSectionDraw( app, @@ -128,6 +135,9 @@ export async function loadThDrawDatas(): Promise { storage.trackLogicSections.forEach((logicSection) => { datas.push(new TrackLogicSectionData(logicSection)); }); + storage.esbButtons.forEach((esbButton) => { + datas.push(new EsbButtonData(esbButton)); + }); refDevicesList = storage.stationRelateDeviceList; return Promise.resolve({ canvasProperty: storage.canvas, @@ -153,6 +163,9 @@ export function saveThDrawDatas(app: IDrawApp) { storage.trackLogicSections.push( (trackLogicSectionData as TrackLogicSectionData).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()); diff --git a/src/drawApp/zdwxApp.ts b/src/drawApp/zdwxApp.ts index 5adeaf1..bd96c34 100644 --- a/src/drawApp/zdwxApp.ts +++ b/src/drawApp/zdwxApp.ts @@ -40,6 +40,13 @@ import { SignalTemplate, Signal } from 'src/graphics/signal/Signal'; import { SignalData, SignalState } from './graphics/SignalInteraction'; import { getCategoryConsts } from './gategoryConsts'; import { CategoryType } from 'src/components/CategoryType'; +import { ZdwxEsbDraw } from 'src/graphics/esbButton/ZdwxEsbDrawAssistant'; +import { ZdwxEsbTemplate } from 'src/graphics/esbButton/ZdwxEsb'; +import { + DrawZdwxEsbInteraction, + ZdwxEsbData, + ZdwxEsbState, +} from './graphics/ZdwxEsbInteraction'; let zdwxDrawApp: IDrawApp | null = null; @@ -102,7 +109,12 @@ export function initZdwxDrawApp(): IDrawApp { new TrackLogicSectionTemplate(new TrackLogicSectionData()) ); new BeaconDraw(app, new BeaconTemplate(new BeaconData())); + new ZdwxEsbDraw( + app, + new ZdwxEsbTemplate(new ZdwxEsbData(), new ZdwxEsbState()) + ); DrawBeaconInteraction.init(app); + DrawZdwxEsbInteraction.init(app); app.addKeyboardListener( new KeyListener({ value: 'KeyS', @@ -187,39 +199,3 @@ export interface RelateDevicelistItem { } let refDevicesList: graphicData.StationRelateDevice[] = []; -export function loadStationRelateDeviceList() { - return refDevicesList; -} - -export function creatStationRelateDevice(row: graphicData.StationRelateDevice) { - refDevicesList.push(row); - zdwxDrawApp?.emit('postdataloaded'); -} - -export function editStationRelateDevice( - editRow: RelateDevicelistItem, - newData: graphicData.StationRelateDevice -) { - for (let i = 0; i < refDevicesList.length; i++) { - if ( - refDevicesList[i].deviceType == editRow.deviceType && - refDevicesList[i].code == editRow.code - ) { - refDevicesList[i] = newData; - break; - } - } - zdwxDrawApp?.emit('postdataloaded'); -} - -export function deleteStationRelateDevice(row: RelateDevicelistItem) { - for (let i = 0; i < refDevicesList.length; i++) { - if ( - refDevicesList[i].deviceType == row.deviceType && - refDevicesList[i].code == row.code - ) { - refDevicesList.splice(i, 1); - break; - } - } -} diff --git a/src/graphics/esbButton/ZdwxEsb.ts b/src/graphics/esbButton/ZdwxEsb.ts new file mode 100644 index 0000000..d567284 --- /dev/null +++ b/src/graphics/esbButton/ZdwxEsb.ts @@ -0,0 +1,103 @@ +import { Graphics } from 'pixi.js'; +import { + GraphicData, + GraphicState, + JlGraphic, + JlGraphicTemplate, + VectorText, +} from 'src/jl-graphic'; + +export interface IZdwxEsbData extends GraphicData { + get code(): string; + set code(v: string); + get flip(): boolean; + set flip(v: boolean); + get index(): number; + set index(v: number); + get refStand(): string; + set refStand(v: string); + clone(): IZdwxEsbData; + copyFrom(data: IZdwxEsbData): void; + eq(other: IZdwxEsbData): boolean; +} + +export interface IZdwxEsbState extends GraphicState { + id: string; + get down(): boolean; + set down(v: boolean); +} + +const zdwxEsbConsts = { + codeFontSize: 12, + codeColor: 0xffffff, + bodyLineColor: 0xff0000, + bodyLineWidth: 2, + bodyRectLineColor: 0xff0000, + bodyRectLineWidth: 1, + bodyRectWidth: 20, + bodyRectHeight: 20, + bodyCircleRadius: 4, + bodyCircleColor: 0xff0000, + bodyColor: 0x000000, + pressedColor: 0xff0000, +}; +export class ZdwxEsb extends JlGraphic { + static Type = 'esbButton'; + codeGraph: VectorText = new VectorText(''); + circleBody: Graphics = new Graphics(); + + constructor() { + super(ZdwxEsb.Type); + this.addChild(this.codeGraph); + this.addChild(this.circleBody); + this.codeGraph.name = 'zdwx_esb_code'; + } + get datas(): IZdwxEsbData { + return this.getDatas(); + } + get state(): IZdwxEsbState { + return this.getStates(); + } + doRepaint(): void { + const codeGraph = this.codeGraph; + codeGraph.text = this.datas.code; + codeGraph.style.fill = zdwxEsbConsts.codeColor; + codeGraph.setVectorFontSize(zdwxEsbConsts.codeFontSize); + codeGraph.anchor.set(0.5); + const codeTransform = this.datas?.childTransforms?.find( + (item) => item.name === 'zdwx_esb_code' + ); + if (codeTransform) { + const position = codeTransform?.transform.position; + const rotation = codeTransform?.transform?.rotation; + codeGraph.position.set(position?.x, position?.y); + codeGraph.rotation = rotation || 0; + } else { + codeGraph.position.set(-30, 0); + } + this.circleBody.clear(); + this.circleBody.lineStyle( + zdwxEsbConsts.bodyLineWidth, + zdwxEsbConsts.bodyCircleColor + ); + this.circleBody.arc(0, 0, zdwxEsbConsts.bodyCircleRadius, Math.PI, 0); + this.circleBody.moveTo(0, 0); + this.circleBody.lineTo(0, 6); + this.circleBody.moveTo(-4, 0); + this.circleBody.lineTo(4, 0); + this.circleBody.drawRect(-9, -9, 20, 20); + this.circleBody.drawRect(-12, -12, 20, 20); + } +} + +export class ZdwxEsbTemplate extends JlGraphicTemplate { + constructor(dataTemplate: IZdwxEsbData, stateTemplate?: IZdwxEsbState) { + super(ZdwxEsb.Type, { dataTemplate, stateTemplate }); + } + new(): ZdwxEsb { + const zdwxEsb = new ZdwxEsb(); + zdwxEsb.loadData(this.datas); + zdwxEsb.loadState(this.states); + return zdwxEsb; + } +} diff --git a/src/graphics/esbButton/ZdwxEsbDrawAssistant.ts b/src/graphics/esbButton/ZdwxEsbDrawAssistant.ts new file mode 100644 index 0000000..d57bdf4 --- /dev/null +++ b/src/graphics/esbButton/ZdwxEsbDrawAssistant.ts @@ -0,0 +1,114 @@ +import { DisplayObject, FederatedMouseEvent, Point } from 'pixi.js'; +import { + AbsorbableLine, + AbsorbablePosition, + GraphicDrawAssistant, + GraphicInteractionPlugin, + GraphicTransformEvent, + IDrawApp, + JlGraphic, +} from 'src/jl-graphic'; +import { ZdwxEsb, ZdwxEsbTemplate, IZdwxEsbData } from './ZdwxEsb'; + +export interface IZdwxEsbDataDrawOptions { + newData: () => IZdwxEsbData; +} +export class ZdwxEsbDraw extends GraphicDrawAssistant< + ZdwxEsbTemplate, + IZdwxEsbData +> { + _zdwxEsb: ZdwxEsb | null = null; + constructor(app: IDrawApp, template: ZdwxEsbTemplate) { + super( + app, + template, + 'svguse:../../drawIcon.svg#icon-zdwx-esb', + '紧急关闭按钮EsbButton' + ); + ZdwxEsbInteraction.init(app); + } + public get zdwxEsb(): ZdwxEsb { + if (!this._zdwxEsb) { + this._zdwxEsb = this.graphicTemplate.new(); + this._zdwxEsb.loadData(this.graphicTemplate.datas); + this.container.addChild(this._zdwxEsb); + } + return this._zdwxEsb; + } + + onLeftUp(e: FederatedMouseEvent): void { + this.container.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(true); + } + + redraw(p: Point): void { + this.zdwxEsb.repaint(); + this.container.position.set(p.x, p.y); + } + + prepareData(data: IZdwxEsbData): boolean { + data.transform = this.container.saveTransform(); + data.code = 'ESB'; + return true; + } +} +/** + * 构建吸附线 + * @param zdwxEsb + */ +function buildAbsorbablePositions(zdwxEsb: ZdwxEsb): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const zdwxEsbs = zdwxEsb.queryStore.queryByType(ZdwxEsb.Type); + const canvas = zdwxEsb.getCanvas(); + zdwxEsbs.forEach((item) => { + if (item.id === zdwxEsb.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 ZdwxEsbInteraction extends GraphicInteractionPlugin { + static Name = 'zdwx_esb_transform'; + constructor(app: IDrawApp) { + super(ZdwxEsbInteraction.Name, app); + } + static init(app: IDrawApp) { + return new ZdwxEsbInteraction(app); + } + filter(...grahpics: JlGraphic[]): ZdwxEsb[] | undefined { + return grahpics + .filter((g) => g.type === ZdwxEsb.Type) + .map((g) => g as ZdwxEsb); + } + bind(g: ZdwxEsb): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + g.on('transformstart', this.transformstart, this); + } + unbind(g: ZdwxEsb): 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 zdwxEsb = target.getGraphic() as ZdwxEsb; + zdwxEsb.getGraphicApp().setOptions({ + absorbablePositions: buildAbsorbablePositions(zdwxEsb), + }); + } +}