From 33ee1eba020d30f5f956f5842dc33db081344969 Mon Sep 17 00:00:00 2001 From: fan Date: Sun, 8 Oct 2023 15:49:54 +0800 Subject: [PATCH] =?UTF-8?q?psl=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bj-rtss-message | 2 +- src/components/draw-app/PslDrawProperties.vue | 5 + .../properties/TextContentProperty.vue | 67 +++++++ .../graphics/TextContentInteraction.ts | 59 ++++++ src/drawApp/pslApp.ts | 13 ++ src/graphics/textContent/TextContent.ts | 71 +++++++ .../textContent/TextContentDrawAssistant.ts | 108 ++++++++++ src/layouts/PslDrawLayout.vue | 8 +- src/protos/device_state.ts | 23 +++ src/protos/pslGraphics.ts | 187 +++++++++++++++++- 10 files changed, 540 insertions(+), 3 deletions(-) create mode 100644 src/components/draw-app/properties/TextContentProperty.vue create mode 100644 src/drawApp/graphics/TextContentInteraction.ts create mode 100644 src/graphics/textContent/TextContent.ts create mode 100644 src/graphics/textContent/TextContentDrawAssistant.ts diff --git a/bj-rtss-message b/bj-rtss-message index 8403e90..da65562 160000 --- a/bj-rtss-message +++ b/bj-rtss-message @@ -1 +1 @@ -Subproject commit 8403e90692f1848d38b7928ba3b9ecfe3f381722 +Subproject commit da65562e424bfc69981acba945214e17974e588d diff --git a/src/components/draw-app/PslDrawProperties.vue b/src/components/draw-app/PslDrawProperties.vue index 976dd99..934ca04 100644 --- a/src/components/draw-app/PslDrawProperties.vue +++ b/src/components/draw-app/PslDrawProperties.vue @@ -24,6 +24,9 @@ + @@ -34,10 +37,12 @@ import { PslButton } from 'src/graphics/pslButton/pslButton'; import { PslLight } from 'src/graphics/pslLight/pslLight'; import { PslKey } from 'src/graphics/pslKey/pslKey'; +import { TextContent } from 'src/graphics/textContent/TextContent'; import CanvasPslProperty from './properties/CanvasPslProperty.vue'; import PslButtonProperty from './properties/PslButtonProperty.vue'; import PslLightProperty from './properties/PslLightProperty.vue'; import PslKeyProperty from './properties/PslKeyProperty.vue'; +import TextContentProperty from './properties/TextContentProperty.vue'; import { usePslDrawStore } from 'src/stores/psl-draw-store'; const pslDrawStore = usePslDrawStore(); diff --git a/src/components/draw-app/properties/TextContentProperty.vue b/src/components/draw-app/properties/TextContentProperty.vue new file mode 100644 index 0000000..991277a --- /dev/null +++ b/src/components/draw-app/properties/TextContentProperty.vue @@ -0,0 +1,67 @@ + + + diff --git a/src/drawApp/graphics/TextContentInteraction.ts b/src/drawApp/graphics/TextContentInteraction.ts new file mode 100644 index 0000000..60c1262 --- /dev/null +++ b/src/drawApp/graphics/TextContentInteraction.ts @@ -0,0 +1,59 @@ +import * as pb_1 from 'google-protobuf'; +import { + ITextContentData, + TextContent, +} from 'src/graphics/textContent/TextContent'; +import { pslGraphicData } from 'src/protos/pslGraphics'; +import { GraphicDataBase } from './GraphicDataBase'; + +export class PslTextData extends GraphicDataBase implements ITextContentData { + constructor(data?: pslGraphicData.PslText) { + let pslText; + if (data) { + pslText = data; + } else { + pslText = new pslGraphicData.PslText({ + common: GraphicDataBase.defaultCommonInfo(TextContent.Type), + }); + } + super(pslText); + } + + public get data(): pslGraphicData.PslText { + return this.getData(); + } + + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get content(): string { + return this.data.content; + } + set content(v: string) { + this.data.content = v; + } + get color(): string { + return this.data.color; + } + set color(v: string) { + this.data.color = v; + } + get fontSize(): number { + return this.data.fontSize; + } + set fontSize(v: number) { + this.data.fontSize = v; + } + clone(): PslTextData { + return new PslTextData(this.data.cloneMessage()); + } + copyFrom(data: PslTextData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: PslTextData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} diff --git a/src/drawApp/pslApp.ts b/src/drawApp/pslApp.ts index b935e94..6dfac7b 100644 --- a/src/drawApp/pslApp.ts +++ b/src/drawApp/pslApp.ts @@ -26,6 +26,12 @@ import { PslButton, PslButtonTemplate } from 'src/graphics/pslButton/pslButton'; import { PslButtonData } from './graphics/PslButtonInteraction'; import { PslLight, PslLightTemplate } from 'src/graphics/pslLight/pslLight'; import { PslLightData } from './graphics/PslLightInteraction'; +import { + TextContent, + TextContentTemplate, +} from 'src/graphics/textContent/TextContent'; +import { PslTextData } from './graphics/TextContentInteraction'; +import { TextContentDraw } from 'src/graphics/textContent/TextContentDrawAssistant'; const UndoOptions: MenuItemOptions = { name: '撤销', @@ -71,6 +77,7 @@ export function initPslDrawApp(): IDrawApp { new PslKeyDraw(app, new PslKeyTemplate(new PslKeyData())); new PslButtonDraw(app, new PslButtonTemplate(new PslButtonData())); new PslLightDraw(app, new PslLightTemplate(new PslLightData())); + new TextContentDraw(app, new TextContentTemplate(new PslTextData())); // 画布右键菜单 app.registerMenu(DefaultCanvasMenu); @@ -167,6 +174,9 @@ export function savePslDrawDatas(app: IDrawApp) { } else if (PslKey.Type === g.type) { const pslKeyData = (g as PslKey).saveData(); storage.pslKeys.push((pslKeyData as PslKeyData).data); + } else if (TextContent.Type === g.type) { + const pslTextData = (g as TextContent).saveData(); + storage.pslTexts.push((pslTextData as PslTextData).data); } }); const base64 = fromUint8Array(storage.serialize()); @@ -200,6 +210,9 @@ export async function loadPslDrawDatas(): Promise { storage.pslKeys.forEach((pslKey) => { datas.push(new PslKeyData(pslKey)); }); + storage.pslTexts.forEach((pslText) => { + datas.push(new PslTextData(pslText)); + }); console.log(datas); console.log(storage); return Promise.resolve({ diff --git a/src/graphics/textContent/TextContent.ts b/src/graphics/textContent/TextContent.ts new file mode 100644 index 0000000..a451931 --- /dev/null +++ b/src/graphics/textContent/TextContent.ts @@ -0,0 +1,71 @@ +import { + GraphicData, + JlGraphic, + JlGraphicTemplate, + VectorText, +} from 'src/jl-graphic'; + +export interface ITextContentData extends GraphicData { + get code(): string; // 编号 + set code(v: string); + get content(): string; + set content(v: string); + get color(): string; + set color(v: string); + get fontSize(): number; + set fontSize(v: number); + clone(): ITextContentData; + copyFrom(data: ITextContentData): void; + eq(other: ITextContentData): boolean; +} + +const textContentConsts = { + defaultContent: '请填写内容', + defaultColor: '0xcccccc', + defaultFontSize: 14, +}; +export class TextContent extends JlGraphic { + static Type = 'textContent'; + contentGraph: VectorText = new VectorText(''); //车站名 + constructor() { + super(TextContent.Type); + this.addChild(this.contentGraph); + } + + get datas(): ITextContentData { + return this.getDatas(); + } + get states(): ITextContentData { + return this.getStates(); + } + doRepaint(): void { + const contentGraph = this.contentGraph; + contentGraph.text = this.datas?.content || textContentConsts.defaultContent; + let color = textContentConsts.defaultColor; + if (this.datas?.color) { + color = this.datas.color.replace('#', '0x'); + } + contentGraph.style.fill = color; + contentGraph.setVectorFontSize( + this.datas?.fontSize || textContentConsts.defaultFontSize + ); + contentGraph.anchor.set(0.5); + } +} + +export class TextContentTemplate extends JlGraphicTemplate { + color: string; + fontSize: number; + constructor(dataTemplate: ITextContentData) { + super(TextContent.Type, { + dataTemplate, + }); + this.color = '#cccccc'; + this.fontSize = 14; + } + new(): TextContent { + const textContent = new TextContent(); + textContent.loadData(this.datas); + return textContent; + } +} diff --git a/src/graphics/textContent/TextContentDrawAssistant.ts b/src/graphics/textContent/TextContentDrawAssistant.ts new file mode 100644 index 0000000..67022a6 --- /dev/null +++ b/src/graphics/textContent/TextContentDrawAssistant.ts @@ -0,0 +1,108 @@ +import { FederatedPointerEvent, Point } from 'pixi.js'; +import { + AbsorbableLine, + AbsorbablePosition, + GraphicDrawAssistant, + GraphicInteractionPlugin, + IDrawApp, + JlGraphic, +} from 'src/jl-graphic'; + +import { + ITextContentData, + TextContent, + TextContentTemplate, +} from './TextContent'; + +export interface ITextContentDrawOptions { + newData: () => ITextContentData; +} + +export class TextContentDraw extends GraphicDrawAssistant< + TextContentTemplate, + ITextContentData +> { + codeGraph: TextContent; + constructor(app: IDrawApp, template: TextContentTemplate) { + super(app, template, 'translate', '文字TextContent'); + this.codeGraph = this.graphicTemplate.new(); + this.container.addChild(this.codeGraph); + textContentInteraction.init(app); + } + + bind(): void { + super.bind(); + this.codeGraph.loadData(this.graphicTemplate.datas); + this.codeGraph.doRepaint(); + } + + clearCache(): void { + //this.codeGraph.destroy(); + } + onLeftDown(e: FederatedPointerEvent): void { + this.container.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(true); + } + + redraw(p: Point): void { + this.container.position.copyFrom(p); + } + prepareData(data: ITextContentData): boolean { + const template = this.graphicTemplate; + data.color = template.color; + data.fontSize = template.fontSize; + data.transform = this.container.saveTransform(); + return true; + } +} + +function buildAbsorbablePositions(station: TextContent): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const stations = station.queryStore.queryByType( + TextContent.Type + ); + const { width } = station.getGraphicApp().canvas; + stations.forEach((other) => { + if (other.id == station.id) { + return; + } + const ps = other.datas.transform.position; + const xs = new AbsorbableLine({ x: 0, y: ps.y }, { x: width, y: ps.y }); + aps.push(xs); + }); + return aps; +} + +export class textContentInteraction extends GraphicInteractionPlugin { + static Name = 'textContent_transform'; + constructor(app: IDrawApp) { + super(textContentInteraction.Name, app); + } + static init(app: IDrawApp) { + return new textContentInteraction(app); + } + filter(...grahpics: JlGraphic[]): TextContent[] | undefined { + return grahpics + .filter((g) => g.type === TextContent.Type) + .map((g) => g as TextContent); + } + bind(g: TextContent): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + g.on('selected', this.onSelected, this); + } + unbind(g: TextContent): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + g.off('selected', this.onSelected, this); + } + onSelected(): void { + const textContent = this.app.selectedGraphics[0] as TextContent; + this.app.setOptions({ + absorbablePositions: buildAbsorbablePositions(textContent), + }); + } +} diff --git a/src/layouts/PslDrawLayout.vue b/src/layouts/PslDrawLayout.vue index 4619799..11ee814 100644 --- a/src/layouts/PslDrawLayout.vue +++ b/src/layouts/PslDrawLayout.vue @@ -124,6 +124,7 @@ import { useQuasar } from 'quasar'; import { PslButton } from 'src/graphics/pslButton/pslButton'; import { PslKey } from 'src/graphics/pslKey/pslKey'; import { PslLight } from 'src/graphics/pslLight/pslLight'; +import { TextContent } from 'src/graphics/textContent/TextContent'; const $q = useQuasar(); const route = useRoute(); @@ -204,7 +205,12 @@ onMounted(() => { pslDrawStore.setDraftId(null); } - const drawAssistantsTypes = [PslKey.Type, PslButton.Type, PslLight.Type]; + const drawAssistantsTypes = [ + PslKey.Type, + PslButton.Type, + PslLight.Type, + TextContent.Type, + ]; drawAssistantsTypes.forEach((type) => { const drawAssistant = getPslDrawApp()?.getDrawAssistant(type); if (drawAssistant) { diff --git a/src/protos/device_state.ts b/src/protos/device_state.ts index aa5aa9a..a756e5e 100644 --- a/src/protos/device_state.ts +++ b/src/protos/device_state.ts @@ -970,6 +970,7 @@ export namespace state { headRadarSpeed?: number; tailRadarSpeed?: number; udpInterruption?: boolean; + acceleration?: number; }) { super(); pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [6], this.#one_of_decls); @@ -1037,6 +1038,9 @@ export namespace state { if ("udpInterruption" in data && data.udpInterruption != undefined) { this.udpInterruption = data.udpInterruption; } + if ("acceleration" in data && data.acceleration != undefined) { + this.acceleration = data.acceleration; + } } } get heartbeat() { @@ -1165,6 +1169,12 @@ export namespace state { set udpInterruption(value: boolean) { pb_1.Message.setField(this, 21, value); } + get acceleration() { + return pb_1.Message.getFieldWithDefault(this, 22, 0) as number; + } + set acceleration(value: number) { + pb_1.Message.setField(this, 22, value); + } static fromObject(data: { heartbeat?: number; headLinkId?: string; @@ -1187,6 +1197,7 @@ export namespace state { headRadarSpeed?: number; tailRadarSpeed?: number; udpInterruption?: boolean; + acceleration?: number; }): TrainDynamicState { const message = new TrainDynamicState({}); if (data.heartbeat != null) { @@ -1252,6 +1263,9 @@ export namespace state { if (data.udpInterruption != null) { message.udpInterruption = data.udpInterruption; } + if (data.acceleration != null) { + message.acceleration = data.acceleration; + } return message; } toObject() { @@ -1277,6 +1291,7 @@ export namespace state { headRadarSpeed?: number; tailRadarSpeed?: number; udpInterruption?: boolean; + acceleration?: number; } = {}; if (this.heartbeat != null) { data.heartbeat = this.heartbeat; @@ -1341,6 +1356,9 @@ export namespace state { if (this.udpInterruption != null) { data.udpInterruption = this.udpInterruption; } + if (this.acceleration != null) { + data.acceleration = this.acceleration; + } return data; } serialize(): Uint8Array; @@ -1389,6 +1407,8 @@ export namespace state { writer.writeInt32(20, this.tailRadarSpeed); if (this.udpInterruption != false) writer.writeBool(21, this.udpInterruption); + if (this.acceleration != 0) + writer.writeFloat(22, this.acceleration); if (!w) return writer.getResultBuffer(); } @@ -1461,6 +1481,9 @@ export namespace state { case 21: message.udpInterruption = reader.readBool(); break; + case 22: + message.acceleration = reader.readFloat(); + break; default: reader.skipField(); } } diff --git a/src/protos/pslGraphics.ts b/src/protos/pslGraphics.ts index d68ba84..dc4ee50 100644 --- a/src/protos/pslGraphics.ts +++ b/src/protos/pslGraphics.ts @@ -18,9 +18,10 @@ export namespace pslGraphicData { pslLights?: PslLight[]; pslButtons?: PslButton[]; pslKeys?: PslKey[]; + pslTexts?: PslText[]; }) { super(); - pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [2, 3, 4], this.#one_of_decls); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [2, 3, 4, 5], this.#one_of_decls); if (!Array.isArray(data) && typeof data == "object") { if ("canvas" in data && data.canvas != undefined) { this.canvas = data.canvas; @@ -34,6 +35,9 @@ export namespace pslGraphicData { if ("pslKeys" in data && data.pslKeys != undefined) { this.pslKeys = data.pslKeys; } + if ("pslTexts" in data && data.pslTexts != undefined) { + this.pslTexts = data.pslTexts; + } } } get canvas() { @@ -63,11 +67,18 @@ export namespace pslGraphicData { set pslKeys(value: PslKey[]) { pb_1.Message.setRepeatedWrapperField(this, 4, value); } + get pslTexts() { + return pb_1.Message.getRepeatedWrapperField(this, PslText, 5) as PslText[]; + } + set pslTexts(value: PslText[]) { + pb_1.Message.setRepeatedWrapperField(this, 5, value); + } static fromObject(data: { canvas?: ReturnType; pslLights?: ReturnType[]; pslButtons?: ReturnType[]; pslKeys?: ReturnType[]; + pslTexts?: ReturnType[]; }): PslGraphicStorage { const message = new PslGraphicStorage({}); if (data.canvas != null) { @@ -82,6 +93,9 @@ export namespace pslGraphicData { if (data.pslKeys != null) { message.pslKeys = data.pslKeys.map(item => PslKey.fromObject(item)); } + if (data.pslTexts != null) { + message.pslTexts = data.pslTexts.map(item => PslText.fromObject(item)); + } return message; } toObject() { @@ -90,6 +104,7 @@ export namespace pslGraphicData { pslLights?: ReturnType[]; pslButtons?: ReturnType[]; pslKeys?: ReturnType[]; + pslTexts?: ReturnType[]; } = {}; if (this.canvas != null) { data.canvas = this.canvas.toObject(); @@ -103,6 +118,9 @@ export namespace pslGraphicData { if (this.pslKeys != null) { data.pslKeys = this.pslKeys.map((item: PslKey) => item.toObject()); } + if (this.pslTexts != null) { + data.pslTexts = this.pslTexts.map((item: PslText) => item.toObject()); + } return data; } serialize(): Uint8Array; @@ -117,6 +135,8 @@ export namespace pslGraphicData { writer.writeRepeatedMessage(3, this.pslButtons, (item: PslButton) => item.serialize(writer)); if (this.pslKeys.length) writer.writeRepeatedMessage(4, this.pslKeys, (item: PslKey) => item.serialize(writer)); + if (this.pslTexts.length) + writer.writeRepeatedMessage(5, this.pslTexts, (item: PslText) => item.serialize(writer)); if (!w) return writer.getResultBuffer(); } @@ -138,6 +158,9 @@ export namespace pslGraphicData { case 4: reader.readMessage(message.pslKeys, () => pb_1.Message.addToRepeatedWrapperField(message, 4, PslKey.deserialize(reader), PslKey)); break; + case 5: + reader.readMessage(message.pslTexts, () => pb_1.Message.addToRepeatedWrapperField(message, 5, PslText.deserialize(reader), PslText)); + break; default: reader.skipField(); } } @@ -475,4 +498,166 @@ export namespace pslGraphicData { return PslKey.deserialize(bytes); } } + export class PslText extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: dependency_1.graphicData.CommonInfo; + code?: string; + content?: string; + color?: string; + fontSize?: number; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("content" in data && data.content != undefined) { + this.content = data.content; + } + if ("color" in data && data.color != undefined) { + this.color = data.color; + } + if ("fontSize" in data && data.fontSize != undefined) { + this.fontSize = data.fontSize; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, dependency_1.graphicData.CommonInfo, 1) as dependency_1.graphicData.CommonInfo; + } + set common(value: dependency_1.graphicData.CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get content() { + return pb_1.Message.getFieldWithDefault(this, 3, "") as string; + } + set content(value: string) { + pb_1.Message.setField(this, 3, value); + } + get color() { + return pb_1.Message.getFieldWithDefault(this, 4, "") as string; + } + set color(value: string) { + pb_1.Message.setField(this, 4, value); + } + get fontSize() { + return pb_1.Message.getFieldWithDefault(this, 5, 0) as number; + } + set fontSize(value: number) { + pb_1.Message.setField(this, 5, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + content?: string; + color?: string; + fontSize?: number; + }): PslText { + const message = new PslText({}); + if (data.common != null) { + message.common = dependency_1.graphicData.CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.content != null) { + message.content = data.content; + } + if (data.color != null) { + message.color = data.color; + } + if (data.fontSize != null) { + message.fontSize = data.fontSize; + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + content?: string; + color?: string; + fontSize?: number; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.content != null) { + data.content = this.content; + } + if (this.color != null) { + data.color = this.color; + } + if (this.fontSize != null) { + data.fontSize = this.fontSize; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.content.length) + writer.writeString(3, this.content); + if (this.color.length) + writer.writeString(4, this.color); + if (this.fontSize != 0) + writer.writeInt32(5, this.fontSize); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): PslText { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new PslText(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = dependency_1.graphicData.CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + message.content = reader.readString(); + break; + case 4: + message.color = reader.readString(); + break; + case 5: + message.fontSize = reader.readInt32(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): PslText { + return PslText.deserialize(bytes); + } + } }