添加紧急关闭按钮

This commit is contained in:
fan 2023-07-26 17:47:50 +08:00
parent 76eac675ee
commit 569c4d8438
10 changed files with 403 additions and 3 deletions

View File

@ -90,6 +90,9 @@
<gated-box-property
v-else-if="drawStore.selectedGraphicType === GatedBox.Type"
></gated-box-property>
<esb-button-property
v-else-if="drawStore.selectedGraphicType === EsbButton.Type"
></esb-button-property>
</q-card-section>
</template>
</q-card>
@ -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();
</script>

View File

@ -0,0 +1,51 @@
<template>
<q-form>
<q-input outlined readonly v-model="esbButtonModel.id" label="id" hint="" />
<q-input
outlined
v-model.number="esbButtonModel.index"
type="number"
@blur="onUpdate"
label="索引"
/>
<q-input
outlined
v-model="esbButtonModel.code"
@blur="onUpdate"
label="名称"
/>
</q-form>
</template>
<script setup lang="ts">
import { EsbButtonData } from 'src/drawApp/graphics/EsbButtonInteraction';
import { EsbButton } from 'src/graphics/esbButton/EsbButton';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, watch } from 'vue';
const drawStore = useDrawStore();
const esbButtonModel = reactive(new EsbButtonData());
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == EsbButton.Type) {
esbButtonModel.copyFrom(val.saveData() as EsbButtonData);
}
}
);
onMounted(() => {
const esbButton = drawStore.selectedGraphic as EsbButton;
if (esbButton) {
esbButtonModel.copyFrom(esbButton.saveData());
}
});
function onUpdate() {
const esbButton = drawStore.selectedGraphic as EsbButton;
if (esbButton) {
drawStore.getDrawApp().updateGraphicAndRecord(esbButton, esbButtonModel);
}
}
</script>

View File

@ -8,6 +8,12 @@
@blur="onUpdate"
label="索引"
/>
<q-input
outlined
v-model="gatedBoxModel.code"
@blur="onUpdate"
label="名称"
/>
</q-form>
</template>

View File

@ -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<graphicData.EsbButton>();
}
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<EsbButton> {
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);
}
}

View File

@ -61,7 +61,7 @@ const flipConfig: MenuItemOptions = {
name: '上下翻转',
};
const GatedBoxEditMenu: ContextMenu = ContextMenu.init({
name: 'Spks开关编辑菜单',
name: '门控箱编辑菜单',
groups: [
{
items: [flipConfig],

View File

@ -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([]);

View File

@ -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<IEsbButton>();
}
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<EsbButton> {
constructor(dataTemplate: IEsbButton) {
super(EsbButton.Type, { dataTemplate });
}
new(): EsbButton {
const esbButton = new EsbButton();
esbButton.loadData(this.datas);
return esbButton;
}
}

View File

@ -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>(
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<EsbButton> {
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),
});
}
}

View File

@ -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();

View File

@ -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();