diff --git a/rtss-proto-msg b/rtss-proto-msg index ea8b911..87726ae 160000 --- a/rtss-proto-msg +++ b/rtss-proto-msg @@ -1 +1 @@ -Subproject commit ea8b911846b63f649a254250ba81c7a804da332a +Subproject commit 87726ae0917aedf814210d9725ee354aa15bb1f9 diff --git a/src/components/draw-app/IscsDrawProperties.vue b/src/components/draw-app/IscsDrawProperties.vue index 94d894a..d1747db 100644 --- a/src/components/draw-app/IscsDrawProperties.vue +++ b/src/components/draw-app/IscsDrawProperties.vue @@ -36,6 +36,9 @@ + @@ -50,7 +53,7 @@ diff --git a/src/components/draw-app/properties/CCTV/CanvasCCTVProperty.vue b/src/components/draw-app/properties/CanvasIscsProperty.vue similarity index 100% rename from src/components/draw-app/properties/CCTV/CanvasCCTVProperty.vue rename to src/components/draw-app/properties/CanvasIscsProperty.vue diff --git a/src/components/draw-app/properties/CircleProperty.vue b/src/components/draw-app/properties/CircleProperty.vue new file mode 100644 index 0000000..1353307 --- /dev/null +++ b/src/components/draw-app/properties/CircleProperty.vue @@ -0,0 +1,94 @@ + + + diff --git a/src/components/draw-app/properties/RectProperty.vue b/src/components/draw-app/properties/RectProperty.vue index bde2876..7c0833c 100644 --- a/src/components/draw-app/properties/RectProperty.vue +++ b/src/components/draw-app/properties/RectProperty.vue @@ -37,7 +37,7 @@ { datas.push(new LineData(line)); }); + storage.commonGraphicStorage.circles.forEach((circle) => { + datas.push(new CircleData(circle)); + }); return datas; } @@ -118,13 +126,20 @@ export function saveCommonDrawDatas(app: IDrawApp, storage: ICommonStorage) { storage.commonGraphicStorage.arrows.push((arrowData as ArrowData).data); } else if (g instanceof TextContent) { const textContentData = g.saveData(); - storage.commonGraphicStorage.texts.push((textContentData as IscsTextData).data); + storage.commonGraphicStorage.texts.push( + (textContentData as IscsTextData).data + ); } else if (g instanceof Rect) { const rectData = g.saveData(); storage.commonGraphicStorage.rects.push((rectData as RectData).data); } else if (g instanceof Line) { const lineData = g.saveData(); storage.commonGraphicStorage.lines.push((lineData as LineData).data); + } else if (g instanceof Circle) { + const circleData = g.saveData(); + storage.commonGraphicStorage.circles.push( + (circleData as CircleData).data + ); } }); @@ -194,11 +209,19 @@ export function handlerNoEditCommonData( break; case Arrow.Type: const arrowData = iscsGraphicData.Arrow.deserialize(data.data); - syncNoEditData(operationType, arrowData, storage.commonGraphicStorage.arrows); + syncNoEditData( + operationType, + arrowData, + storage.commonGraphicStorage.arrows + ); break; case TextContent.Type: const iscsTextData = iscsGraphicData.Text.deserialize(data.data); - syncNoEditData(operationType, iscsTextData, storage.commonGraphicStorage.texts); + syncNoEditData( + operationType, + iscsTextData, + storage.commonGraphicStorage.texts + ); break; } } diff --git a/src/drawApp/graphics/CircleInteraction.ts b/src/drawApp/graphics/CircleInteraction.ts new file mode 100644 index 0000000..db4e426 --- /dev/null +++ b/src/drawApp/graphics/CircleInteraction.ts @@ -0,0 +1,76 @@ +import * as pb_1 from 'google-protobuf'; +import { IPointData } from 'pixi.js'; +import { ICircleData, Circle } from 'src/graphics/circle/Circle'; +import { iscsGraphicData } from 'src/protos/iscs_graphic_data'; +import { GraphicDataBase } from './GraphicDataBase'; +import { common } from 'src/protos/common'; + +export class CircleData extends GraphicDataBase implements ICircleData { + constructor(data?: iscsGraphicData.Circle) { + let circle; + if (!data) { + circle = new iscsGraphicData.Circle({ + common: GraphicDataBase.defaultCommonInfo(Circle.Type), + }); + } else { + circle = data; + } + super(circle); + } + + public get data(): iscsGraphicData.Circle { + return this.getData(); + } + + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get lineWidth(): number { + return this.data.lineWidth; + } + set lineWidth(v: number) { + this.data.lineWidth = v; + } + get lineColor(): string { + return this.data.lineColor; + } + set lineColor(v: string) { + this.data.lineColor = v; + } + get position(): IPointData { + return this.data.position; + } + set position(point: IPointData) { + this.data.position = new common.Point({ x: point.x, y: point.y }); + } + get radius(): number { + return this.data.radius; + } + set radius(v: number) { + this.data.radius = v; + } + get fillColor(): string { + return this.data.fillColor; + } + set fillColor(v: string) { + this.data.fillColor = v; + } + get alpha(): number { + return this.data.alpha; + } + set alpha(v: number) { + this.data.alpha = v; + } + clone(): CircleData { + return new CircleData(this.data.cloneMessage()); + } + copyFrom(data: CircleData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: CircleData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} diff --git a/src/graphics/circle/Circle.ts b/src/graphics/circle/Circle.ts new file mode 100644 index 0000000..0fe040f --- /dev/null +++ b/src/graphics/circle/Circle.ts @@ -0,0 +1,86 @@ +import { Color, Graphics, IPointData } from 'pixi.js'; +import { GraphicData, JlGraphic, JlGraphicTemplate } from 'jl-graphic'; + +export interface ICircleData extends GraphicData { + get code(): string; // 编号 + set code(v: string); + get position(): IPointData; // 位置坐标 + set position(point: IPointData); + get radius(): number; // 圆的半径 + set radius(v: number); + get lineWidth(): number; // 线宽 + set lineWidth(v: number); + get lineColor(): string; // 线色 + set lineColor(v: string); + get fillColor(): string; // 填充色 + set fillColor(v: string); + get alpha(): number; // 透明度 + set alpha(v: number); + clone(): ICircleData; + copyFrom(data: ICircleData): void; + eq(other: ICircleData): boolean; +} + +const circleConsts = { + lineWidth: 2, + lineColor: '0xff0000', + fillColor: '0xff0000', + alpha: 0.001, +}; + +export class Circle extends JlGraphic { + static Type = 'Circle'; + circleGraphic: Graphics = new Graphics(); + constructor() { + super(Circle.Type); + this.addChild(this.circleGraphic); + } + + get datas(): ICircleData { + return this.getDatas(); + } + doRepaint(): void { + const circleGraphic = this.circleGraphic; + circleGraphic.clear(); + circleGraphic.lineStyle( + this.datas.lineWidth, + new Color(this.datas.lineColor) + ); + circleGraphic.beginFill(this.datas.fillColor, this.datas.alpha); + circleGraphic.drawCircle( + this.datas.position.x, + this.datas.position.y, + this.datas.radius + ); + circleGraphic.endFill; + circleGraphic.pivot = this.datas.position; + const transformPos = this.datas.transform.position; + if (transformPos.x == 0 && transformPos.y == 0) { + this.position.set(this.datas.position.x, this.datas.position.y); + } else { + this.position.set( + this.datas.transform.position.x, + this.datas.transform.position.y + ); + } + } +} + +export class CircleTemplate extends JlGraphicTemplate { + lineWidth: number; + lineColor: string; + fillColor: string; + alpha: number; + constructor(dataTemplate: ICircleData) { + super(Circle.Type, { + dataTemplate, + }); + this.lineWidth = circleConsts.lineWidth; + this.lineColor = circleConsts.lineColor; + this.fillColor = circleConsts.fillColor; + this.alpha = circleConsts.alpha; + } + new(): Circle { + return new Circle(); + } +} diff --git a/src/graphics/circle/CircleDrawAssistant.ts b/src/graphics/circle/CircleDrawAssistant.ts new file mode 100644 index 0000000..902c0ed --- /dev/null +++ b/src/graphics/circle/CircleDrawAssistant.ts @@ -0,0 +1,117 @@ +import { FederatedPointerEvent, Graphics, IHitArea, Point } from 'pixi.js'; +import { + circlePoint2, + GraphicDrawAssistant, + GraphicInteractionPlugin, + IDrawApp, + JlGraphic, +} from 'jl-graphic'; + +import { ICircleData, Circle, CircleTemplate } from './Circle'; + +export class CircleDraw extends GraphicDrawAssistant< + CircleTemplate, + ICircleData +> { + point1: Point | null = null; + point2: Point | null = null; + circleGraphic: Graphics = new Graphics(); + + constructor(app: IDrawApp, template: CircleTemplate) { + super(app, template, 'sym_o_circle', '圆Circle'); + this.container.addChild(this.circleGraphic); + circleInteraction.init(app); + } + + clearCache(): void { + this.circleGraphic.clear(); + } + onLeftDown(e: FederatedPointerEvent): void { + const { x, y } = this.toCanvasCoordinates(e.global); + const p = new Point(x, y); + if (this.point1 === null) { + this.point1 = p; + } else { + this.point2 = p; + this.createAndStore(true); + this.point1 = null; + this.point2 = null; + } + } + + redraw(p: Point): void { + const template = this.graphicTemplate; + if (this.point1 === null) return; + const circleGraphic = this.circleGraphic; + circleGraphic.clear(); + circleGraphic.lineStyle(template.lineWidth, template.lineColor); + circleGraphic.drawCircle(...this.normalize(this.point1, p)); + } + private normalize(p1: Point, p2: Point): [number, number, number] { + const { abs } = Math; + const x = p1.x < p2.x ? p1.x : p2.x; + const y = p1.y < p2.y ? p1.y : p2.y; + const r = abs(p1.x - p2.x); + return [x, y, r]; + } + prepareData(data: ICircleData): boolean { + const p1 = this.point1 as Point; + const p2 = this.point2 as Point; + const [x, y, radius] = this.normalize(p1, p2); + const template = this.graphicTemplate; + data.position = new Point(x, y); + data.lineWidth = template.lineWidth; + data.lineColor = template.lineColor; + data.fillColor = template.fillColor; + data.alpha = template.alpha; + data.radius = radius; + return true; + } +} + +//碰撞检测 +export class CircleGraphicHitArea implements IHitArea { + circle: Circle; + constructor(circle: Circle) { + this.circle = circle; + } + contains(x: number, y: number): boolean { + const datas = this.circle.datas; + const tolerance = datas.lineWidth; + return circlePoint2( + datas.position.x, + datas.position.y, + Math.abs(datas.radius), + x, + y, + tolerance + ); + } +} + +export class circleInteraction extends GraphicInteractionPlugin { + static Name = 'circle_transform'; + constructor(app: IDrawApp) { + super(circleInteraction.Name, app); + } + static init(app: IDrawApp) { + return new circleInteraction(app); + } + filter(...grahpics: JlGraphic[]): Circle[] | undefined { + return grahpics + .filter((g) => g.type === Circle.Type) + .map((g) => g as Circle); + } + bind(g: Circle): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + g.circleGraphic.hitArea = new CircleGraphicHitArea(g); + } + unbind(g: Circle): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + } +} diff --git a/src/graphics/line/LineDrawAssistant.ts b/src/graphics/line/LineDrawAssistant.ts index e6384e9..2fa48bb 100644 --- a/src/graphics/line/LineDrawAssistant.ts +++ b/src/graphics/line/LineDrawAssistant.ts @@ -110,14 +110,6 @@ export class LineDraw extends GraphicDrawAssistant { } } - onRightClick(): void { - if (this.points.length < 2) { - this.finish(); - return; - } - this.createAndStore(true); - } - onEsc(): void { if (this.points.length < 2) { this.finish(); diff --git a/src/graphics/rect/RectDrawAssistant.ts b/src/graphics/rect/RectDrawAssistant.ts index 987f0a0..ec179f0 100644 --- a/src/graphics/rect/RectDrawAssistant.ts +++ b/src/graphics/rect/RectDrawAssistant.ts @@ -9,10 +9,6 @@ import { import { IRectData, Rect, RectTemplate } from './Rect'; -export interface IRectDrawOptions { - newData: () => IRectData; -} - export class RectDraw extends GraphicDrawAssistant { point1: Point | null = null; point2: Point | null = null; @@ -96,7 +92,7 @@ export class RectGraphicHitArea implements IHitArea { } } export class rectInteraction extends GraphicInteractionPlugin { - static Name = 'platform_transform'; + static Name = 'rect_transform'; constructor(app: IDrawApp) { super(rectInteraction.Name, app); } diff --git a/src/layouts/IscsDrawLayout.vue b/src/layouts/IscsDrawLayout.vue index 9521940..0075626 100644 --- a/src/layouts/IscsDrawLayout.vue +++ b/src/layouts/IscsDrawLayout.vue @@ -262,6 +262,7 @@ import { Line } from 'src/graphics/line/Line'; import { JlOperation } from 'jl-graphic'; import { common } from 'src/protos/common'; import { toStorageTransform } from 'src/drawApp/graphics/GraphicDataBase'; +import { Circle } from 'src/graphics/circle/Circle'; const $q = useQuasar(); const route = useRoute(); @@ -336,6 +337,7 @@ function handleUtilsOption() { const drawAssistantsTypes = [ Arrow.Type, TextContent.Type, + Circle.Type, Rect.Type, Line.Type, ]; @@ -356,6 +358,7 @@ function handleUtilsOption() { ); } }); + drawDialogHeight.value = 0; drawDialogHeight.value = 44 * Math.ceil(utilsOption.length / 2); } //左侧功能按钮 diff --git a/src/protos/iscs_graphic_data.ts b/src/protos/iscs_graphic_data.ts index cd45fc6..3faa48c 100644 --- a/src/protos/iscs_graphic_data.ts +++ b/src/protos/iscs_graphic_data.ts @@ -216,9 +216,10 @@ export namespace iscsGraphicData { texts?: Text[]; rects?: Rect[]; lines?: Line[]; + circles?: Circle[]; }) { super(); - pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [1, 2, 3, 4], this.#one_of_decls); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [1, 2, 3, 4, 5], this.#one_of_decls); if (!Array.isArray(data) && typeof data == "object") { if ("arrows" in data && data.arrows != undefined) { this.arrows = data.arrows; @@ -232,6 +233,9 @@ export namespace iscsGraphicData { if ("lines" in data && data.lines != undefined) { this.lines = data.lines; } + if ("circles" in data && data.circles != undefined) { + this.circles = data.circles; + } } } get arrows() { @@ -258,11 +262,18 @@ export namespace iscsGraphicData { set lines(value: Line[]) { pb_1.Message.setRepeatedWrapperField(this, 4, value); } + get circles() { + return pb_1.Message.getRepeatedWrapperField(this, Circle, 5) as Circle[]; + } + set circles(value: Circle[]) { + pb_1.Message.setRepeatedWrapperField(this, 5, value); + } static fromObject(data: { arrows?: ReturnType[]; texts?: ReturnType[]; rects?: ReturnType[]; lines?: ReturnType[]; + circles?: ReturnType[]; }): CommonGraphicStorage { const message = new CommonGraphicStorage({}); if (data.arrows != null) { @@ -277,6 +288,9 @@ export namespace iscsGraphicData { if (data.lines != null) { message.lines = data.lines.map(item => Line.fromObject(item)); } + if (data.circles != null) { + message.circles = data.circles.map(item => Circle.fromObject(item)); + } return message; } toObject() { @@ -285,6 +299,7 @@ export namespace iscsGraphicData { texts?: ReturnType[]; rects?: ReturnType[]; lines?: ReturnType[]; + circles?: ReturnType[]; } = {}; if (this.arrows != null) { data.arrows = this.arrows.map((item: Arrow) => item.toObject()); @@ -298,6 +313,9 @@ export namespace iscsGraphicData { if (this.lines != null) { data.lines = this.lines.map((item: Line) => item.toObject()); } + if (this.circles != null) { + data.circles = this.circles.map((item: Circle) => item.toObject()); + } return data; } serialize(): Uint8Array; @@ -312,6 +330,8 @@ export namespace iscsGraphicData { writer.writeRepeatedMessage(3, this.rects, (item: Rect) => item.serialize(writer)); if (this.lines.length) writer.writeRepeatedMessage(4, this.lines, (item: Line) => item.serialize(writer)); + if (this.circles.length) + writer.writeRepeatedMessage(5, this.circles, (item: Circle) => item.serialize(writer)); if (!w) return writer.getResultBuffer(); } @@ -333,6 +353,9 @@ export namespace iscsGraphicData { case 4: reader.readMessage(message.lines, () => pb_1.Message.addToRepeatedWrapperField(message, 4, Line.deserialize(reader), Line)); break; + case 5: + reader.readMessage(message.circles, () => pb_1.Message.addToRepeatedWrapperField(message, 5, Circle.deserialize(reader), Circle)); + break; default: reader.skipField(); } } @@ -1111,6 +1134,240 @@ export namespace iscsGraphicData { return Line.deserialize(bytes); } } + export class Circle extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: dependency_1.common.CommonInfo; + code?: string; + position?: dependency_1.common.Point; + radius?: number; + lineWidth?: number; + lineColor?: string; + fillColor?: string; + alpha?: 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 ("position" in data && data.position != undefined) { + this.position = data.position; + } + if ("radius" in data && data.radius != undefined) { + this.radius = data.radius; + } + if ("lineWidth" in data && data.lineWidth != undefined) { + this.lineWidth = data.lineWidth; + } + if ("lineColor" in data && data.lineColor != undefined) { + this.lineColor = data.lineColor; + } + if ("fillColor" in data && data.fillColor != undefined) { + this.fillColor = data.fillColor; + } + if ("alpha" in data && data.alpha != undefined) { + this.alpha = data.alpha; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, dependency_1.common.CommonInfo, 1) as dependency_1.common.CommonInfo; + } + set common(value: dependency_1.common.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 position() { + return pb_1.Message.getWrapperField(this, dependency_1.common.Point, 3) as dependency_1.common.Point; + } + set position(value: dependency_1.common.Point) { + pb_1.Message.setWrapperField(this, 3, value); + } + get has_position() { + return pb_1.Message.getField(this, 3) != null; + } + get radius() { + return pb_1.Message.getFieldWithDefault(this, 4, 0) as number; + } + set radius(value: number) { + pb_1.Message.setField(this, 4, value); + } + get lineWidth() { + return pb_1.Message.getFieldWithDefault(this, 5, 0) as number; + } + set lineWidth(value: number) { + pb_1.Message.setField(this, 5, value); + } + get lineColor() { + return pb_1.Message.getFieldWithDefault(this, 6, "") as string; + } + set lineColor(value: string) { + pb_1.Message.setField(this, 6, value); + } + get fillColor() { + return pb_1.Message.getFieldWithDefault(this, 7, "") as string; + } + set fillColor(value: string) { + pb_1.Message.setField(this, 7, value); + } + get alpha() { + return pb_1.Message.getFieldWithDefault(this, 8, 0) as number; + } + set alpha(value: number) { + pb_1.Message.setField(this, 8, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + position?: ReturnType; + radius?: number; + lineWidth?: number; + lineColor?: string; + fillColor?: string; + alpha?: number; + }): Circle { + const message = new Circle({}); + if (data.common != null) { + message.common = dependency_1.common.CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.position != null) { + message.position = dependency_1.common.Point.fromObject(data.position); + } + if (data.radius != null) { + message.radius = data.radius; + } + if (data.lineWidth != null) { + message.lineWidth = data.lineWidth; + } + if (data.lineColor != null) { + message.lineColor = data.lineColor; + } + if (data.fillColor != null) { + message.fillColor = data.fillColor; + } + if (data.alpha != null) { + message.alpha = data.alpha; + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + position?: ReturnType; + radius?: number; + lineWidth?: number; + lineColor?: string; + fillColor?: string; + alpha?: number; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.position != null) { + data.position = this.position.toObject(); + } + if (this.radius != null) { + data.radius = this.radius; + } + if (this.lineWidth != null) { + data.lineWidth = this.lineWidth; + } + if (this.lineColor != null) { + data.lineColor = this.lineColor; + } + if (this.fillColor != null) { + data.fillColor = this.fillColor; + } + if (this.alpha != null) { + data.alpha = this.alpha; + } + 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.has_position) + writer.writeMessage(3, this.position, () => this.position.serialize(writer)); + if (this.radius != 0) + writer.writeFloat(4, this.radius); + if (this.lineWidth != 0) + writer.writeInt32(5, this.lineWidth); + if (this.lineColor.length) + writer.writeString(6, this.lineColor); + if (this.fillColor.length) + writer.writeString(7, this.fillColor); + if (this.alpha != 0) + writer.writeFloat(8, this.alpha); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Circle { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Circle(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = dependency_1.common.CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + reader.readMessage(message.position, () => message.position = dependency_1.common.Point.deserialize(reader)); + break; + case 4: + message.radius = reader.readFloat(); + break; + case 5: + message.lineWidth = reader.readInt32(); + break; + case 6: + message.lineColor = reader.readString(); + break; + case 7: + message.fillColor = reader.readString(); + break; + case 8: + message.alpha = reader.readFloat(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Circle { + return Circle.deserialize(bytes); + } + } export class CCTVButton extends pb_1.Message { #one_of_decls: number[][] = []; constructor(data?: any[] | {