diff --git a/public/drawIcon.svg b/public/drawIcon.svg
index 5945578..2e28dae 100644
--- a/public/drawIcon.svg
+++ b/public/drawIcon.svg
@@ -75,4 +75,10 @@
+
+
+
+
+
+
diff --git a/src/assets/quasar-logo-vertical.svg b/src/assets/quasar-logo-vertical.svg
index 8210831..87a1eee 100644
--- a/src/assets/quasar-logo-vertical.svg
+++ b/src/assets/quasar-logo-vertical.svg
@@ -12,4 +12,4 @@
-
\ No newline at end of file
+
diff --git a/src/components/draw-app/DrawProperties.vue b/src/components/draw-app/DrawProperties.vue
index da7b322..810e384 100644
--- a/src/components/draw-app/DrawProperties.vue
+++ b/src/components/draw-app/DrawProperties.vue
@@ -139,6 +139,15 @@
drawStore.selectedGraphicType === ConcentrationDividingLine.Type
"
/>
+
+
+
@@ -217,6 +226,12 @@ import { TrackLogicSection } from 'src/graphics/trackLogicSection/TrackLogicSect
import MultipleSelectProperty from './properties/multipleSelectProperty.vue';
import { DepartureTimer } from 'src/graphics/departureTimer/DepartureTimer';
import DepartureTimerProperty from './properties/DepartureTimerProperty.vue';
+import FloodGateProperty from './properties/FloodGateProperty.vue';
+import { FloodGate } from 'src/graphics/floodGate/FloodGate';
+import GarageDoorProperty from './properties/GarageDoorProperty.vue';
+import { GarageDoor } from 'src/graphics/garageDoor/GarageDoor';
+import CarWashingProperty from './properties/CarWashingProperty.vue';
+import { CarWashing } from 'src/graphics/carWashing/CarWashing';
const drawStore = useDrawStore();
diff --git a/src/components/draw-app/properties/CarWashingProperty.vue b/src/components/draw-app/properties/CarWashingProperty.vue
new file mode 100644
index 0000000..cf94636
--- /dev/null
+++ b/src/components/draw-app/properties/CarWashingProperty.vue
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+ {{ getName(id) }}
+
+
+
+
+
+
+
diff --git a/src/components/draw-app/properties/FloodGateProperty.vue b/src/components/draw-app/properties/FloodGateProperty.vue
new file mode 100644
index 0000000..ddefe34
--- /dev/null
+++ b/src/components/draw-app/properties/FloodGateProperty.vue
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+ {{ getName(id) }}
+
+
+
+
+
+
+
diff --git a/src/components/draw-app/properties/GarageDoorProperty.vue b/src/components/draw-app/properties/GarageDoorProperty.vue
new file mode 100644
index 0000000..d537b75
--- /dev/null
+++ b/src/components/draw-app/properties/GarageDoorProperty.vue
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+ {{ getName(id) }}
+
+
+
+
+
+
+
diff --git a/src/drawApp/common.ts b/src/drawApp/common.ts
index 7032344..217c39e 100644
--- a/src/drawApp/common.ts
+++ b/src/drawApp/common.ts
@@ -21,6 +21,9 @@ import { Turnout } from 'src/graphics/turnout/Turnout';
import { ConcentrationDividingLine } from 'src/graphics/concentrationDividingLine/ConcentrationDividingLine';
import { IbpBox } from 'src/graphics/ibpBox/IbpBox';
import { PslBox } from 'src/graphics/pslBox/PslBox';
+import { GarageDoor } from 'src/graphics/garageDoor/GarageDoor';
+import { CarWashing } from 'src/graphics/carWashing/CarWashing';
+import { FloodGate } from 'src/graphics/floodGate/FloodGate';
export const drawCommonLayerList = [
// 图层列表 默认显示的图层defaultShow: true
@@ -55,4 +58,7 @@ export const drawCommonLayerList = [
value: ConcentrationDividingLine.Type,
defaultShow: true,
},
+ { label: '防淹门', value: GarageDoor.Type, defaultShow: true },
+ { label: '车库门', value: FloodGate.Type, defaultShow: true },
+ { label: '洗车机', value: CarWashing.Type, defaultShow: true },
];
diff --git a/src/drawApp/commonApp.ts b/src/drawApp/commonApp.ts
index 205c19f..5079ef6 100644
--- a/src/drawApp/commonApp.ts
+++ b/src/drawApp/commonApp.ts
@@ -142,6 +142,21 @@ import { Dialog } from 'quasar';
import { useDrawStore } from 'src/stores/draw-store';
import { saveDraft } from 'src/api/DraftApi';
import { SignalDraw } from 'src/graphics/signal/SignalDrawAssistant';
+import { CarWashingData } from './graphics/CarWashingInteraction';
+import {
+ CarWashing,
+ CarWashingTemplate,
+} from 'src/graphics/carWashing/CarWashing';
+import { CarWashingDraw } from 'src/graphics/carWashing/CarWashingDrawAssistant';
+import { FloodGateData } from './graphics/FloodGateInteraction';
+import { FloodGate, FloodGateTemplate } from 'src/graphics/floodGate/FloodGate';
+import { FloodGateDraw } from 'src/graphics/floodGate/FloodGateDrawAssistant';
+import { GarageDoorData } from './graphics/GarageDoorInteraction';
+import {
+ GarageDoor,
+ GarageDoorTemplate,
+} from 'src/graphics/garageDoor/GarageDoor';
+import { GarageDoorDraw } from 'src/graphics/garageDoor/GarageDoorDrawAssistant';
const UndoOptions: MenuItemOptions = {
name: '撤销',
@@ -228,6 +243,9 @@ export function initCommonDrawApp(app: IDrawApp) {
app,
new ConcentrationDividingLineTemplate(new ConcentrationDividingLineData())
);
+ new CarWashingDraw(app, new CarWashingTemplate(new CarWashingData()));
+ new FloodGateDraw(app, new FloodGateTemplate(new FloodGateData()));
+ new GarageDoorDraw(app, new GarageDoorTemplate(new GarageDoorData()));
DrawSignalInteraction.init(app);
DrawStopPositionInteraction.init(app);
DrawSpksSwitchInteraction.init(app);
@@ -437,6 +455,15 @@ export function loadCommonDrawDatas(
storage.concentrationDividingLines.forEach((concentrationDividingLine) => {
datas.push(new ConcentrationDividingLineData(concentrationDividingLine));
});
+ storage.floodGates.forEach((flood) => {
+ datas.push(new FloodGateData(flood));
+ });
+ storage.carWashings.forEach((carWashing) => {
+ datas.push(new CarWashingData(carWashing));
+ });
+ storage.garageDoors.forEach((garageDoor) => {
+ datas.push(new GarageDoorData(garageDoor));
+ });
return datas;
}
@@ -523,6 +550,15 @@ export function saveCommonDrawDatas(app: IDrawApp) {
storage.concentrationDividingLines.push(
(concentrationDividingLineData as ConcentrationDividingLineData).data
);
+ } else if (g instanceof CarWashing) {
+ const carWashingData = g.saveData();
+ storage.carWashings.push((carWashingData as CarWashingData).data);
+ } else if (g instanceof FloodGate) {
+ const floodGateData = g.saveData();
+ storage.floodGates.push((floodGateData as FloodGateData).data);
+ } else if (g instanceof GarageDoor) {
+ const garageDoorData = g.saveData();
+ storage.garageDoors.push((garageDoorData as GarageDoorData).data);
}
});
// storage.Platforms.forEach((item) => {
diff --git a/src/drawApp/graphics/CarWashingInteraction.ts b/src/drawApp/graphics/CarWashingInteraction.ts
new file mode 100644
index 0000000..5a49967
--- /dev/null
+++ b/src/drawApp/graphics/CarWashingInteraction.ts
@@ -0,0 +1,88 @@
+import * as pb_1 from 'google-protobuf';
+import { FederatedMouseEvent } from 'pixi.js';
+import {
+ CarWashing,
+ ICarWashingData,
+} from 'src/graphics/carWashing/CarWashing';
+import { GraphicInteractionPlugin, JlGraphic, IGraphicScene } from 'jl-graphic';
+
+import { graphicData } from 'src/protos/stationLayoutGraphics';
+import { GraphicDataBase } from './GraphicDataBase';
+
+export class CarWashingData extends GraphicDataBase implements ICarWashingData {
+ constructor(data?: graphicData.CarWashing) {
+ let carWashing;
+ if (!data) {
+ carWashing = new graphicData.CarWashing({
+ common: GraphicDataBase.defaultCommonInfo(CarWashing.Type),
+ });
+ } else {
+ carWashing = data;
+ }
+ super(carWashing);
+ }
+
+ public get data(): graphicData.CarWashing {
+ return this.getData();
+ }
+ get code(): string {
+ return this.data.code;
+ }
+ set code(v: string) {
+ this.data.code = v;
+ }
+ get linkSection(): number {
+ return this.data.linkSection;
+ }
+ set linkSection(v: number) {
+ this.data.linkSection = v;
+ }
+ get centralizedStations(): number[] {
+ return this.data.centralizedStations;
+ }
+ set centralizedStations(v: number[]) {
+ this.data.centralizedStations = v;
+ }
+ clone(): CarWashingData {
+ return new CarWashingData(this.data.cloneMessage());
+ }
+ copyFrom(data: CarWashingData): void {
+ pb_1.Message.copyInto(data.data, this.data);
+ }
+ eq(other: CarWashingData): boolean {
+ return pb_1.Message.equals(this.data, other.data);
+ }
+}
+
+export class CarWashingOperationInteraction extends GraphicInteractionPlugin {
+ static Name = 'car_washing_operation';
+ constructor(scene: IGraphicScene) {
+ super(CarWashingOperationInteraction.Name, scene);
+ }
+ static init(scene: IGraphicScene) {
+ return new CarWashingOperationInteraction(scene);
+ }
+ filter(...grahpics: JlGraphic[]): CarWashing[] | undefined {
+ return grahpics.filter((g): g is CarWashing => g.type === CarWashing.Type);
+ }
+ bind(g: CarWashing): void {
+ g.eventMode = 'static';
+ g.cursor = 'pointer';
+ g.on('mousedown', this.onPress, this);
+ }
+ unbind(g: CarWashing): void {
+ g.eventMode = 'none';
+ g.cursor = 'default';
+ g.off('mousedown', this.onPress, this);
+ }
+ onPress(e: FederatedMouseEvent) {
+ const g = e.target as CarWashing;
+ g.on('mouseleave', this.onRelease, this);
+ g.on('mouseup', this.onRelease, this);
+ }
+ onRelease(e: FederatedMouseEvent) {
+ const g = e.target as CarWashing;
+ g.off('mouseleave', this.onRelease, this);
+ g.off('mouseup', this.onRelease, this);
+ }
+}
diff --git a/src/drawApp/graphics/FloodGateInteraction.ts b/src/drawApp/graphics/FloodGateInteraction.ts
new file mode 100644
index 0000000..7240566
--- /dev/null
+++ b/src/drawApp/graphics/FloodGateInteraction.ts
@@ -0,0 +1,85 @@
+import * as pb_1 from 'google-protobuf';
+import { FederatedMouseEvent } from 'pixi.js';
+import { FloodGate, IFloodGateData } from 'src/graphics/floodGate/FloodGate';
+import { GraphicInteractionPlugin, JlGraphic, IGraphicScene } from 'jl-graphic';
+
+import { graphicData } from 'src/protos/stationLayoutGraphics';
+import { GraphicDataBase } from './GraphicDataBase';
+
+export class FloodGateData extends GraphicDataBase implements IFloodGateData {
+ constructor(data?: graphicData.FloodGate) {
+ let floodGate;
+ if (!data) {
+ floodGate = new graphicData.FloodGate({
+ common: GraphicDataBase.defaultCommonInfo(FloodGate.Type),
+ });
+ } else {
+ floodGate = data;
+ }
+ super(floodGate);
+ }
+
+ public get data(): graphicData.FloodGate {
+ return this.getData();
+ }
+ get code(): string {
+ return this.data.code;
+ }
+ set code(v: string) {
+ this.data.code = v;
+ }
+ get linkSection(): number {
+ return this.data.linkSection;
+ }
+ set linkSection(v: number) {
+ this.data.linkSection = v;
+ }
+ get centralizedStations(): number[] {
+ return this.data.centralizedStations;
+ }
+ set centralizedStations(v: number[]) {
+ this.data.centralizedStations = v;
+ }
+ clone(): FloodGateData {
+ return new FloodGateData(this.data.cloneMessage());
+ }
+ copyFrom(data: FloodGateData): void {
+ pb_1.Message.copyInto(data.data, this.data);
+ }
+ eq(other: FloodGateData): boolean {
+ return pb_1.Message.equals(this.data, other.data);
+ }
+}
+
+export class FloodGateOperationInteraction extends GraphicInteractionPlugin {
+ static Name = 'flood_gate_operation';
+ constructor(scene: IGraphicScene) {
+ super(FloodGateOperationInteraction.Name, scene);
+ }
+ static init(scene: IGraphicScene) {
+ return new FloodGateOperationInteraction(scene);
+ }
+ filter(...grahpics: JlGraphic[]): FloodGate[] | undefined {
+ return grahpics.filter((g): g is FloodGate => g.type === FloodGate.Type);
+ }
+ bind(g: FloodGate): void {
+ g.eventMode = 'static';
+ g.cursor = 'pointer';
+ g.on('mousedown', this.onPress, this);
+ }
+ unbind(g: FloodGate): void {
+ g.eventMode = 'none';
+ g.cursor = 'default';
+ g.off('mousedown', this.onPress, this);
+ }
+ onPress(e: FederatedMouseEvent) {
+ const g = e.target as FloodGate;
+ g.on('mouseleave', this.onRelease, this);
+ g.on('mouseup', this.onRelease, this);
+ }
+ onRelease(e: FederatedMouseEvent) {
+ const g = e.target as FloodGate;
+ g.off('mouseleave', this.onRelease, this);
+ g.off('mouseup', this.onRelease, this);
+ }
+}
diff --git a/src/drawApp/graphics/GarageDoorInteraction.ts b/src/drawApp/graphics/GarageDoorInteraction.ts
new file mode 100644
index 0000000..381b1f8
--- /dev/null
+++ b/src/drawApp/graphics/GarageDoorInteraction.ts
@@ -0,0 +1,88 @@
+import * as pb_1 from 'google-protobuf';
+import { FederatedMouseEvent } from 'pixi.js';
+import {
+ GarageDoor,
+ IGarageDoorData,
+} from 'src/graphics/garageDoor/GarageDoor';
+import { GraphicInteractionPlugin, JlGraphic, IGraphicScene } from 'jl-graphic';
+
+import { graphicData } from 'src/protos/stationLayoutGraphics';
+import { GraphicDataBase } from './GraphicDataBase';
+
+export class GarageDoorData extends GraphicDataBase implements IGarageDoorData {
+ constructor(data?: graphicData.GarageDoor) {
+ let garageDoor;
+ if (!data) {
+ garageDoor = new graphicData.GarageDoor({
+ common: GraphicDataBase.defaultCommonInfo(GarageDoor.Type),
+ });
+ } else {
+ garageDoor = data;
+ }
+ super(garageDoor);
+ }
+
+ public get data(): graphicData.GarageDoor {
+ return this.getData();
+ }
+ get code(): string {
+ return this.data.code;
+ }
+ set code(v: string) {
+ this.data.code = v;
+ }
+ get linkSection(): number {
+ return this.data.linkSection;
+ }
+ set linkSection(v: number) {
+ this.data.linkSection = v;
+ }
+ get centralizedStations(): number[] {
+ return this.data.centralizedStations;
+ }
+ set centralizedStations(v: number[]) {
+ this.data.centralizedStations = v;
+ }
+ clone(): GarageDoorData {
+ return new GarageDoorData(this.data.cloneMessage());
+ }
+ copyFrom(data: GarageDoorData): void {
+ pb_1.Message.copyInto(data.data, this.data);
+ }
+ eq(other: GarageDoorData): boolean {
+ return pb_1.Message.equals(this.data, other.data);
+ }
+}
+
+export class GarageDoorOperationInteraction extends GraphicInteractionPlugin {
+ static Name = 'garage_door_operation';
+ constructor(scene: IGraphicScene) {
+ super(GarageDoorOperationInteraction.Name, scene);
+ }
+ static init(scene: IGraphicScene) {
+ return new GarageDoorOperationInteraction(scene);
+ }
+ filter(...grahpics: JlGraphic[]): GarageDoor[] | undefined {
+ return grahpics.filter((g): g is GarageDoor => g.type === GarageDoor.Type);
+ }
+ bind(g: GarageDoor): void {
+ g.eventMode = 'static';
+ g.cursor = 'pointer';
+ g.on('mousedown', this.onPress, this);
+ }
+ unbind(g: GarageDoor): void {
+ g.eventMode = 'none';
+ g.cursor = 'default';
+ g.off('mousedown', this.onPress, this);
+ }
+ onPress(e: FederatedMouseEvent) {
+ const g = e.target as GarageDoor;
+ g.on('mouseleave', this.onRelease, this);
+ g.on('mouseup', this.onRelease, this);
+ }
+ onRelease(e: FederatedMouseEvent) {
+ const g = e.target as GarageDoor;
+ g.off('mouseleave', this.onRelease, this);
+ g.off('mouseup', this.onRelease, this);
+ }
+}
diff --git a/src/drawApp/lineScene.ts b/src/drawApp/lineScene.ts
index 63be7ee..e3a8ec8 100644
--- a/src/drawApp/lineScene.ts
+++ b/src/drawApp/lineScene.ts
@@ -21,6 +21,27 @@ import {
Signal,
KilometerSystem,
} from 'src/graphics/signal/Signal';
+import {
+ FloodGateData,
+ FloodGateOperationInteraction,
+} from './graphics/FloodGateInteraction';
+import { FloodGate, FloodGateTemplate } from 'src/graphics/floodGate/FloodGate';
+import {
+ CarWashingData,
+ CarWashingOperationInteraction,
+} from './graphics/CarWashingInteraction';
+import {
+ CarWashing,
+ CarWashingTemplate,
+} from 'src/graphics/carWashing/CarWashing';
+import {
+ GarageDoorData,
+ GarageDoorOperationInteraction,
+} from './graphics/GarageDoorInteraction';
+import {
+ GarageDoor,
+ GarageDoorTemplate,
+} from 'src/graphics/garageDoor/GarageDoor';
import {
PlatformData,
PlatformOperateInteraction,
@@ -161,10 +182,16 @@ import {
import { errorNotify, successNotify } from 'src/utils/CommonNotify';
import { removeAllTrain } from 'src/api/Simulation';
import { ApiError } from 'src/boot/axios';
-import { IbpBox,IbpBoxTemplate } from 'src/graphics/ibpBox/IbpBox';
-import { PslBox,PslBoxTemplate } from 'src/graphics/pslBox/PslBox';
-import { PslBoxData, PslBoxOperateInteraction } from './graphics/PslBoxInteraction';
-import { IbpBoxData, IbpBoxOperateInteraction } from './graphics/IbpBoxInteraction';
+import { IbpBox, IbpBoxTemplate } from 'src/graphics/ibpBox/IbpBox';
+import { PslBox, PslBoxTemplate } from 'src/graphics/pslBox/PslBox';
+import {
+ PslBoxData,
+ PslBoxOperateInteraction,
+} from './graphics/PslBoxInteraction';
+import {
+ IbpBoxData,
+ IbpBoxOperateInteraction,
+} from './graphics/IbpBoxInteraction';
const showOptions: MenuItemOptions = {
name: '显示控制',
@@ -227,6 +254,9 @@ export const layerList = [
{ label: '轨道区段', value: TrackSection.Type, defaultShow: false },
{ label: '轨道逻辑区段', value: TrackLogicSection.Type, defaultShow: false },
{ label: '自动折返按钮箱', value: AutoReturnBox.Type, defaultShow: true },
+ { label: '防淹门', value: GarageDoor.Type, defaultShow: true },
+ { label: '车库门', value: FloodGate.Type, defaultShow: true },
+ { label: '洗车机', value: CarWashing.Type, defaultShow: true },
];
let lineScene: IGraphicScene;
@@ -295,6 +325,9 @@ export function initLineScene(lineApp: IGraphicApp, sceneName: string) {
new AutoReturnBoxData(),
new AutoReturnBoxState()
),
+ new CarWashingTemplate(new CarWashingData()),
+ new GarageDoorTemplate(new GarageDoorData()),
+ new FloodGateTemplate(new FloodGateData()),
];
lineScene.registerGraphicTemplates(...graphicTemplate);
SignalOperateInteraction.init(lineScene);
@@ -311,6 +344,9 @@ export function initLineScene(lineApp: IGraphicApp, sceneName: string) {
AutoReturnBoxOperationInteraction.init(lineScene);
PslBoxOperateInteraction.init(lineScene);
IbpBoxOperateInteraction.init(lineScene);
+ CarWashingOperationInteraction.init(lineScene);
+ GarageDoorOperationInteraction.init(lineScene);
+ FloodGateOperationInteraction.init(lineScene);
if (categoryType === CategoryType.TH) {
GatedBoxOperateInteraction.init(lineScene);
}
@@ -606,6 +642,15 @@ export async function loadLineDatas(): Promise {
storage.pslBoxs.forEach((pslBox) => {
datas.push(new PslBoxData(pslBox));
});
+ storage.carWashings.forEach((carWashing) => {
+ datas.push(new CarWashingData(carWashing));
+ });
+ storage.garageDoors.forEach((garageDoor) => {
+ datas.push(new GarageDoorData(garageDoor));
+ });
+ storage.floodGates.forEach((floodGate) => {
+ datas.push(new FloodGateData(floodGate));
+ });
// const linkIdGenerator = new IdGenerator(Link.Type);
// storage.CalculateLink.forEach((link) => {
// const g = new LinkData(link);
diff --git a/src/graphics/carWashing/CarWashing.ts b/src/graphics/carWashing/CarWashing.ts
new file mode 100644
index 0000000..c88e273
--- /dev/null
+++ b/src/graphics/carWashing/CarWashing.ts
@@ -0,0 +1,89 @@
+import { Graphics } from 'pixi.js';
+import {
+ GraphicData,
+ JlGraphic,
+ JlGraphicTemplate,
+ VectorText,
+} from 'jl-graphic';
+
+export interface ICarWashingData extends GraphicData {
+ get code(): string;
+ set code(v: string);
+ get linkSection(): number;
+ set linkSection(v: number);
+ get centralizedStations(): number[];
+ set centralizedStations(v: number[]);
+ clone(): ICarWashingData;
+ copyFrom(data: ICarWashingData): void;
+ eq(other: ICarWashingData): boolean;
+}
+
+const carWashingConsts = {
+ codeFontSize: 12,
+ codeColor: 0xffffff,
+ bodyRectLineColor: 0xffffff,
+ bodyRectLineWidth: 2,
+ bodyRectWidth: 10,
+ bodyRectHeight: 20,
+ bodyColor: 0x000000,
+};
+export class CarWashing extends JlGraphic {
+ static Type = 'carWashing';
+ codeGraph: VectorText = new VectorText('');
+ rectBody: Graphics = new Graphics();
+
+ constructor() {
+ super(CarWashing.Type);
+ this.addChild(this.codeGraph);
+ this.addChild(this.rectBody);
+ this.codeGraph.name = 'carw_code';
+ }
+ get code(): string {
+ return this.datas.code;
+ }
+ get datas(): ICarWashingData {
+ return this.getDatas();
+ }
+ doRepaint(): void {
+ const codeGraph = this.codeGraph;
+ codeGraph.text = this.datas.code;
+ codeGraph.style.fill = carWashingConsts.codeColor;
+ codeGraph.setVectorFontSize(carWashingConsts.codeFontSize);
+ codeGraph.anchor.set(0.5);
+ const codeTransform = this.datas?.childTransforms?.find(
+ (item) => item.name === 'carw_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(0, -30);
+ }
+ this.rectBody.clear();
+ this.rectBody.beginFill(carWashingConsts.bodyColor, 0);
+ this.rectBody.lineStyle(
+ carWashingConsts.bodyRectLineWidth,
+ carWashingConsts.bodyRectLineColor
+ );
+ this.rectBody.drawRect(
+ -carWashingConsts.bodyRectWidth / 2,
+ -carWashingConsts.bodyRectHeight / 2,
+ carWashingConsts.bodyRectWidth,
+ carWashingConsts.bodyRectHeight
+ );
+ this.rectBody.endFill();
+ }
+}
+
+export class CarWashingTemplate extends JlGraphicTemplate {
+ constructor(dataTemplate: ICarWashingData) {
+ super(CarWashing.Type, { dataTemplate });
+ }
+ new(): CarWashing {
+ const carWashing = new CarWashing();
+ carWashing.loadData(this.datas);
+ return carWashing;
+ }
+}
diff --git a/src/graphics/carWashing/CarWashingDrawAssistant.ts b/src/graphics/carWashing/CarWashingDrawAssistant.ts
new file mode 100644
index 0000000..bdc92a7
--- /dev/null
+++ b/src/graphics/carWashing/CarWashingDrawAssistant.ts
@@ -0,0 +1,128 @@
+import { DisplayObject, FederatedMouseEvent, Point } from 'pixi.js';
+import {
+ AbsorbableLine,
+ AbsorbablePosition,
+ GraphicDrawAssistant,
+ GraphicInteractionPlugin,
+ GraphicTransformEvent,
+ IDrawApp,
+ JlGraphic,
+} from 'jl-graphic';
+import { CarWashing, CarWashingTemplate, ICarWashingData } from './CarWashing';
+
+export interface ICarWashingDataDrawOptions {
+ newData: () => ICarWashingData;
+}
+export class CarWashingDraw extends GraphicDrawAssistant<
+ CarWashingTemplate,
+ ICarWashingData
+> {
+ _carWashing: CarWashing | null = null;
+ constructor(app: IDrawApp, template: CarWashingTemplate) {
+ super(
+ app,
+ template,
+ 'svguse:../../drawIcon.svg#icon-car-washing',
+ '洗车机CarWashing'
+ );
+ CarWashingInteraction.init(app);
+ }
+ public get carWashing(): CarWashing {
+ if (!this._carWashing) {
+ this._carWashing = this.graphicTemplate.new();
+ this._carWashing.loadData(this.graphicTemplate.datas);
+ this.container.addChild(this._carWashing);
+ }
+ return this._carWashing;
+ }
+
+ onLeftUp(e: FederatedMouseEvent): void {
+ this.container.position.copyFrom(this.toCanvasCoordinates(e.global));
+ this.createAndStore(true);
+ }
+
+ redraw(p: Point): void {
+ this.carWashing.repaint();
+ this.container.position.set(p.x, p.y);
+ }
+
+ prepareData(data: ICarWashingData): boolean {
+ data.transform = this.container.saveTransform();
+ data.code = 'CarWash';
+ return true;
+ }
+}
+/**
+ * 构建吸附线
+ * @param carWashing
+ */
+function buildAbsorbablePositions(
+ carWashing: CarWashing
+): AbsorbablePosition[] {
+ const aps: AbsorbablePosition[] = [];
+ const carWashings = carWashing.queryStore.queryByType(
+ CarWashing.Type
+ );
+ const canvas = carWashing.getCanvas();
+ carWashings.forEach((item) => {
+ if (item.id === carWashing.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 CarWashingInteraction extends GraphicInteractionPlugin {
+ static Name = 'car_washing_transform';
+ constructor(app: IDrawApp) {
+ super(CarWashingInteraction.Name, app);
+ }
+ static init(app: IDrawApp) {
+ return new CarWashingInteraction(app);
+ }
+ filter(...grahpics: JlGraphic[]): CarWashing[] | undefined {
+ return grahpics
+ .filter((g) => g.type === CarWashing.Type)
+ .map((g) => g as CarWashing);
+ }
+ bind(g: CarWashing): void {
+ g.eventMode = 'static';
+ g.cursor = 'pointer';
+ g.scalable = true;
+ g.rotatable = true;
+ g.codeGraph.draggable = true;
+ g.codeGraph.selectable = true;
+ g.codeGraph.rotatable = true;
+ g.codeGraph.transformSave = true;
+ g.codeGraph.eventMode = 'static';
+ g.on('transformstart', this.transformstart, this);
+ }
+ unbind(g: CarWashing): void {
+ g.eventMode = 'none';
+ g.scalable = false;
+ g.rotatable = false;
+ g.codeGraph.draggable = false;
+ g.codeGraph.selectable = false;
+ g.codeGraph.rotatable = false;
+ g.codeGraph.transformSave = false;
+ g.codeGraph.eventMode = 'none';
+ g.off('transformstart', this.transformstart, this);
+ }
+ transformstart(e: GraphicTransformEvent) {
+ const target = e.target as DisplayObject;
+ const carWashing = target.getGraphic() as CarWashing;
+ carWashing.getGraphicApp().setOptions({
+ absorbablePositions: buildAbsorbablePositions(carWashing),
+ });
+ }
+}
diff --git a/src/graphics/floodGate/FloodGate.ts b/src/graphics/floodGate/FloodGate.ts
new file mode 100644
index 0000000..512f5e6
--- /dev/null
+++ b/src/graphics/floodGate/FloodGate.ts
@@ -0,0 +1,99 @@
+import { Graphics } from 'pixi.js';
+import {
+ GraphicData,
+ JlGraphic,
+ JlGraphicTemplate,
+ VectorText,
+} from 'jl-graphic';
+
+export interface IFloodGateData extends GraphicData {
+ get code(): string;
+ set code(v: string);
+ get linkSection(): number;
+ set linkSection(v: number);
+ get centralizedStations(): number[];
+ set centralizedStations(v: number[]);
+ clone(): IFloodGateData;
+ copyFrom(data: IFloodGateData): void;
+ eq(other: IFloodGateData): boolean;
+}
+
+const floodGateConsts = {
+ codeFontSize: 12,
+ codeColor: 0xffffff,
+ bodyLineColor: 0xffffff,
+ bodyLineWidth: 2,
+ bodyColor: 0x000000,
+ bodyRectWidth: 10,
+ bodyRectHeight: 20,
+};
+export class FloodGate extends JlGraphic {
+ static Type = 'floodGate';
+ codeGraph: VectorText = new VectorText('');
+ lineBody: Graphics = new Graphics();
+
+ constructor() {
+ super(FloodGate.Type);
+ this.addChild(this.codeGraph);
+ this.addChild(this.lineBody);
+ this.codeGraph.name = 'flood_code';
+ }
+ get code(): string {
+ return this.datas.code;
+ }
+ get datas(): IFloodGateData {
+ return this.getDatas();
+ }
+ doRepaint(): void {
+ const codeGraph = this.codeGraph;
+ codeGraph.text = this.datas.code;
+ codeGraph.style.fill = floodGateConsts.codeColor;
+ codeGraph.setVectorFontSize(floodGateConsts.codeFontSize);
+ codeGraph.anchor.set(0.5);
+ const codeTransform = this.datas?.childTransforms?.find(
+ (item) => item.name === 'flood_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(0, -30);
+ }
+ this.lineBody.clear();
+ this.lineBody.lineStyle(
+ floodGateConsts.bodyLineWidth,
+ floodGateConsts.bodyLineColor
+ );
+ this.lineBody.moveTo(
+ -floodGateConsts.bodyRectWidth / 2,
+ -floodGateConsts.bodyRectHeight / 2
+ );
+ this.lineBody.lineTo(
+ floodGateConsts.bodyRectWidth / 2,
+ -floodGateConsts.bodyRectHeight / 2
+ );
+ this.lineBody.moveTo(
+ -floodGateConsts.bodyRectWidth / 2,
+ floodGateConsts.bodyRectHeight / 2
+ );
+ this.lineBody.lineTo(
+ floodGateConsts.bodyRectWidth / 2,
+ floodGateConsts.bodyRectHeight / 2
+ );
+ this.lineBody.moveTo(0, -floodGateConsts.bodyRectHeight / 2);
+ this.lineBody.lineTo(0, floodGateConsts.bodyRectHeight / 2);
+ }
+}
+
+export class FloodGateTemplate extends JlGraphicTemplate {
+ constructor(dataTemplate: IFloodGateData) {
+ super(FloodGate.Type, { dataTemplate });
+ }
+ new(): FloodGate {
+ const floodGate = new FloodGate();
+ floodGate.loadData(this.datas);
+ return floodGate;
+ }
+}
diff --git a/src/graphics/floodGate/FloodGateDrawAssistant.ts b/src/graphics/floodGate/FloodGateDrawAssistant.ts
new file mode 100644
index 0000000..1808a5c
--- /dev/null
+++ b/src/graphics/floodGate/FloodGateDrawAssistant.ts
@@ -0,0 +1,126 @@
+import { DisplayObject, FederatedMouseEvent, Point } from 'pixi.js';
+import {
+ AbsorbableLine,
+ AbsorbablePosition,
+ GraphicDrawAssistant,
+ GraphicInteractionPlugin,
+ GraphicTransformEvent,
+ IDrawApp,
+ JlGraphic,
+} from 'jl-graphic';
+import { FloodGate, FloodGateTemplate, IFloodGateData } from './FloodGate';
+
+export interface IFloodGateDataDrawOptions {
+ newData: () => IFloodGateData;
+}
+export class FloodGateDraw extends GraphicDrawAssistant<
+ FloodGateTemplate,
+ IFloodGateData
+> {
+ _floodGate: FloodGate | null = null;
+ constructor(app: IDrawApp, template: FloodGateTemplate) {
+ super(
+ app,
+ template,
+ 'svguse:../../drawIcon.svg#icon-flood-gate',
+ '车库门FloodGate'
+ );
+ FloodGateInteraction.init(app);
+ }
+ public get floodGate(): FloodGate {
+ if (!this._floodGate) {
+ this._floodGate = this.graphicTemplate.new();
+ this._floodGate.loadData(this.graphicTemplate.datas);
+ this.container.addChild(this._floodGate);
+ }
+ return this._floodGate;
+ }
+
+ onLeftUp(e: FederatedMouseEvent): void {
+ this.container.position.copyFrom(this.toCanvasCoordinates(e.global));
+ this.createAndStore(true);
+ }
+
+ redraw(p: Point): void {
+ this.floodGate.repaint();
+ this.container.position.set(p.x, p.y);
+ }
+
+ prepareData(data: IFloodGateData): boolean {
+ data.transform = this.container.saveTransform();
+ data.code = 'FloodGate';
+ return true;
+ }
+}
+/**
+ * 构建吸附线
+ * @param floodGate
+ */
+function buildAbsorbablePositions(floodGate: FloodGate): AbsorbablePosition[] {
+ const aps: AbsorbablePosition[] = [];
+ const floodGates = floodGate.queryStore.queryByType(
+ FloodGate.Type
+ );
+ const canvas = floodGate.getCanvas();
+ floodGates.forEach((item) => {
+ if (item.id === floodGate.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 FloodGateInteraction extends GraphicInteractionPlugin {
+ static Name = 'flood_gate_transform';
+ constructor(app: IDrawApp) {
+ super(FloodGateInteraction.Name, app);
+ }
+ static init(app: IDrawApp) {
+ return new FloodGateInteraction(app);
+ }
+ filter(...grahpics: JlGraphic[]): FloodGate[] | undefined {
+ return grahpics
+ .filter((g) => g.type === FloodGate.Type)
+ .map((g) => g as FloodGate);
+ }
+ bind(g: FloodGate): void {
+ g.eventMode = 'static';
+ g.cursor = 'pointer';
+ g.scalable = true;
+ g.rotatable = true;
+ g.codeGraph.draggable = true;
+ g.codeGraph.selectable = true;
+ g.codeGraph.rotatable = true;
+ g.codeGraph.transformSave = true;
+ g.codeGraph.eventMode = 'static';
+ g.on('transformstart', this.transformstart, this);
+ }
+ unbind(g: FloodGate): void {
+ g.eventMode = 'none';
+ g.scalable = false;
+ g.rotatable = false;
+ g.codeGraph.draggable = false;
+ g.codeGraph.selectable = false;
+ g.codeGraph.rotatable = false;
+ g.codeGraph.transformSave = false;
+ g.codeGraph.eventMode = 'none';
+ g.off('transformstart', this.transformstart, this);
+ }
+ transformstart(e: GraphicTransformEvent) {
+ const target = e.target as DisplayObject;
+ const floodGate = target.getGraphic() as FloodGate;
+ floodGate.getGraphicApp().setOptions({
+ absorbablePositions: buildAbsorbablePositions(floodGate),
+ });
+ }
+}
diff --git a/src/graphics/garageDoor/GarageDoor.ts b/src/graphics/garageDoor/GarageDoor.ts
new file mode 100644
index 0000000..4b9d2e5
--- /dev/null
+++ b/src/graphics/garageDoor/GarageDoor.ts
@@ -0,0 +1,99 @@
+import { Graphics } from 'pixi.js';
+import {
+ GraphicData,
+ JlGraphic,
+ JlGraphicTemplate,
+ VectorText,
+} from 'jl-graphic';
+
+export interface IGarageDoorData extends GraphicData {
+ get code(): string;
+ set code(v: string);
+ get linkSection(): number;
+ set linkSection(v: number);
+ get centralizedStations(): number[];
+ set centralizedStations(v: number[]);
+ clone(): IGarageDoorData;
+ copyFrom(data: IGarageDoorData): void;
+ eq(other: IGarageDoorData): boolean;
+}
+
+const garageConsts = {
+ codeFontSize: 12,
+ codeColor: 0xffffff,
+ bodyLineColor: 0xffffff,
+ bodyLineWidth: 2,
+ bodyColor: 0x000000,
+ bodyRectWidth: 10,
+ bodyRectHeight: 20,
+};
+export class GarageDoor extends JlGraphic {
+ static Type = 'garageDoor';
+ codeGraph: VectorText = new VectorText('');
+ lineBody: Graphics = new Graphics();
+
+ constructor() {
+ super(GarageDoor.Type);
+ this.addChild(this.codeGraph);
+ this.addChild(this.lineBody);
+ this.codeGraph.name = 'garage_code';
+ }
+ get code(): string {
+ return this.datas.code;
+ }
+ get datas(): IGarageDoorData {
+ return this.getDatas();
+ }
+ doRepaint(): void {
+ const codeGraph = this.codeGraph;
+ codeGraph.text = this.datas.code;
+ codeGraph.style.fill = garageConsts.codeColor;
+ codeGraph.setVectorFontSize(garageConsts.codeFontSize);
+ codeGraph.anchor.set(0.5);
+ const codeTransform = this.datas?.childTransforms?.find(
+ (item) => item.name === 'garage_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(0, -30);
+ }
+ this.lineBody.clear();
+ this.lineBody.lineStyle(
+ garageConsts.bodyLineWidth,
+ garageConsts.bodyLineColor
+ );
+ this.lineBody.moveTo(
+ -garageConsts.bodyRectWidth / 2,
+ -garageConsts.bodyRectHeight / 2
+ );
+ this.lineBody.lineTo(
+ garageConsts.bodyRectWidth / 2,
+ -garageConsts.bodyRectHeight / 2
+ );
+ this.lineBody.moveTo(
+ -garageConsts.bodyRectWidth / 2,
+ garageConsts.bodyRectHeight / 2
+ );
+ this.lineBody.lineTo(
+ garageConsts.bodyRectWidth / 2,
+ garageConsts.bodyRectHeight / 2
+ );
+ this.lineBody.moveTo(0, -garageConsts.bodyRectHeight / 2);
+ this.lineBody.lineTo(0, garageConsts.bodyRectHeight / 2);
+ }
+}
+
+export class GarageDoorTemplate extends JlGraphicTemplate {
+ constructor(dataTemplate: IGarageDoorData) {
+ super(GarageDoor.Type, { dataTemplate });
+ }
+ new(): GarageDoor {
+ const garageDoor = new GarageDoor();
+ garageDoor.loadData(this.datas);
+ return garageDoor;
+ }
+}
diff --git a/src/graphics/garageDoor/GarageDoorDrawAssistant.ts b/src/graphics/garageDoor/GarageDoorDrawAssistant.ts
new file mode 100644
index 0000000..da7f0aa
--- /dev/null
+++ b/src/graphics/garageDoor/GarageDoorDrawAssistant.ts
@@ -0,0 +1,128 @@
+import { DisplayObject, FederatedMouseEvent, Point } from 'pixi.js';
+import {
+ AbsorbableLine,
+ AbsorbablePosition,
+ GraphicDrawAssistant,
+ GraphicInteractionPlugin,
+ GraphicTransformEvent,
+ IDrawApp,
+ JlGraphic,
+} from 'jl-graphic';
+import { GarageDoor, GarageDoorTemplate, IGarageDoorData } from './GarageDoor';
+
+export interface IGarageDoorDataDrawOptions {
+ newData: () => IGarageDoorData;
+}
+export class GarageDoorDraw extends GraphicDrawAssistant<
+ GarageDoorTemplate,
+ IGarageDoorData
+> {
+ _garageDoor: GarageDoor | null = null;
+ constructor(app: IDrawApp, template: GarageDoorTemplate) {
+ super(
+ app,
+ template,
+ 'svguse:../../drawIcon.svg#icon-flood-gate',
+ '防淹门GarageDoor'
+ );
+ GarageDoorInteraction.init(app);
+ }
+ public get garageDoor(): GarageDoor {
+ if (!this._garageDoor) {
+ this._garageDoor = this.graphicTemplate.new();
+ this._garageDoor.loadData(this.graphicTemplate.datas);
+ this.container.addChild(this._garageDoor);
+ }
+ return this._garageDoor;
+ }
+
+ onLeftUp(e: FederatedMouseEvent): void {
+ this.container.position.copyFrom(this.toCanvasCoordinates(e.global));
+ this.createAndStore(true);
+ }
+
+ redraw(p: Point): void {
+ this.garageDoor.repaint();
+ this.container.position.set(p.x, p.y);
+ }
+
+ prepareData(data: IGarageDoorData): boolean {
+ data.transform = this.container.saveTransform();
+ data.code = 'GarageDoor';
+ return true;
+ }
+}
+/**
+ * 构建吸附线
+ * @param garageDoor
+ */
+function buildAbsorbablePositions(
+ garageDoor: GarageDoor
+): AbsorbablePosition[] {
+ const aps: AbsorbablePosition[] = [];
+ const garageDoors = garageDoor.queryStore.queryByType(
+ GarageDoor.Type
+ );
+ const canvas = garageDoor.getCanvas();
+ garageDoors.forEach((item) => {
+ if (item.id === garageDoor.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 GarageDoorInteraction extends GraphicInteractionPlugin {
+ static Name = 'garage_door_transform';
+ constructor(app: IDrawApp) {
+ super(GarageDoorInteraction.Name, app);
+ }
+ static init(app: IDrawApp) {
+ return new GarageDoorInteraction(app);
+ }
+ filter(...grahpics: JlGraphic[]): GarageDoor[] | undefined {
+ return grahpics
+ .filter((g) => g.type === GarageDoor.Type)
+ .map((g) => g as GarageDoor);
+ }
+ bind(g: GarageDoor): void {
+ g.eventMode = 'static';
+ g.cursor = 'pointer';
+ g.scalable = true;
+ g.rotatable = true;
+ g.codeGraph.draggable = true;
+ g.codeGraph.selectable = true;
+ g.codeGraph.rotatable = true;
+ g.codeGraph.transformSave = true;
+ g.codeGraph.eventMode = 'static';
+ g.on('transformstart', this.transformstart, this);
+ }
+ unbind(g: GarageDoor): void {
+ g.eventMode = 'none';
+ g.scalable = false;
+ g.rotatable = false;
+ g.codeGraph.draggable = false;
+ g.codeGraph.selectable = false;
+ g.codeGraph.rotatable = false;
+ g.codeGraph.transformSave = false;
+ g.codeGraph.eventMode = 'none';
+ g.off('transformstart', this.transformstart, this);
+ }
+ transformstart(e: GraphicTransformEvent) {
+ const target = e.target as DisplayObject;
+ const garageDoor = target.getGraphic() as GarageDoor;
+ garageDoor.getGraphicApp().setOptions({
+ absorbablePositions: buildAbsorbablePositions(garageDoor),
+ });
+ }
+}
diff --git a/src/layouts/DrawLayout.vue b/src/layouts/DrawLayout.vue
index 0c59f40..e80826f 100644
--- a/src/layouts/DrawLayout.vue
+++ b/src/layouts/DrawLayout.vue
@@ -274,6 +274,9 @@ import SignalDirectionConfig from 'src/components/draw-app/properties/SignalDire
import { distance2, JlGraphic } from 'jl-graphic';
import { IbpBox } from 'src/graphics/ibpBox/IbpBox';
import { PslBox } from 'src/graphics/pslBox/PslBox';
+import { CarWashing } from 'src/graphics/carWashing/CarWashing';
+import { FloodGate } from 'src/graphics/floodGate/FloodGate';
+import { GarageDoor } from 'src/graphics/garageDoor/GarageDoor';
const $q = useQuasar();
const route = useRoute();
@@ -439,6 +442,9 @@ onMounted(() => {
ConcentrationDividingLine.Type,
IbpBox.Type,
PslBox.Type,
+ CarWashing.Type,
+ FloodGate.Type,
+ GarageDoor.Type,
];
switch (drawStore.categoryType) {
case CategoryType.TH: