公共的图形——圆
This commit is contained in:
parent
c5beb9fbfd
commit
8dc7214ceb
@ -1 +1 @@
|
|||||||
Subproject commit ea8b911846b63f649a254250ba81c7a804da332a
|
Subproject commit 87726ae0917aedf814210d9725ee354aa15bb1f9
|
@ -36,6 +36,9 @@
|
|||||||
<line-property
|
<line-property
|
||||||
v-else-if="drawStore.selectedGraphicType === Line.Type"
|
v-else-if="drawStore.selectedGraphicType === Line.Type"
|
||||||
/>
|
/>
|
||||||
|
<circle-property
|
||||||
|
v-else-if="drawStore.selectedGraphicType === Circle.Type"
|
||||||
|
/>
|
||||||
<cctv-button-property
|
<cctv-button-property
|
||||||
v-else-if="drawStore.selectedGraphicType === CCTVButton.Type"
|
v-else-if="drawStore.selectedGraphicType === CCTVButton.Type"
|
||||||
/>
|
/>
|
||||||
@ -50,7 +53,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useDrawStore } from 'src/stores/draw-store';
|
import { useDrawStore } from 'src/stores/draw-store';
|
||||||
import CanvasProperty from './properties/CCTV/CanvasCCTVProperty.vue';
|
import CanvasProperty from './properties/CanvasIscsProperty.vue';
|
||||||
import IscsTextProperty from './properties/IscsTextProperty.vue';
|
import IscsTextProperty from './properties/IscsTextProperty.vue';
|
||||||
import { TextContent } from 'src/graphics/textContent/TextContent';
|
import { TextContent } from 'src/graphics/textContent/TextContent';
|
||||||
import cctvButtonProperty from './properties/CCTV/CCTVButtonProperty.vue';
|
import cctvButtonProperty from './properties/CCTV/CCTVButtonProperty.vue';
|
||||||
@ -60,6 +63,8 @@ import { Rect } from 'src/graphics/rect/Rect';
|
|||||||
import LineTemplate from './templates/LineTemplate.vue';
|
import LineTemplate from './templates/LineTemplate.vue';
|
||||||
import LineProperty from './properties/LineProperty.vue';
|
import LineProperty from './properties/LineProperty.vue';
|
||||||
import { Line } from 'src/graphics/line/Line';
|
import { Line } from 'src/graphics/line/Line';
|
||||||
|
import CircleProperty from './properties/CircleProperty.vue';
|
||||||
|
import { Circle } from 'src/graphics/circle/Circle';
|
||||||
|
|
||||||
const drawStore = useDrawStore();
|
const drawStore = useDrawStore();
|
||||||
</script>
|
</script>
|
||||||
|
94
src/components/draw-app/properties/CircleProperty.vue
Normal file
94
src/components/draw-app/properties/CircleProperty.vue
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<q-form class="q-gutter-sm">
|
||||||
|
<q-input outlined readonly v-model="circleModel.id" label="id" />
|
||||||
|
<q-input
|
||||||
|
outlined
|
||||||
|
v-model.number="circleModel.lineWidth"
|
||||||
|
type="number"
|
||||||
|
@blur="onUpdate"
|
||||||
|
label="线宽"
|
||||||
|
lazy-rules
|
||||||
|
:rules="[(val) => (val && val > 0) || '线宽必须大于0']"
|
||||||
|
/>
|
||||||
|
<q-input
|
||||||
|
outlined
|
||||||
|
v-model="circleModel.lineColor"
|
||||||
|
@blur="onUpdate"
|
||||||
|
label="线色"
|
||||||
|
lazy-rules
|
||||||
|
:rules="[(val) => (val && val.length > 0) || '线色不能为空']"
|
||||||
|
>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon name="colorize" class="cursor-pointer">
|
||||||
|
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
|
||||||
|
<q-color
|
||||||
|
v-model="circleModel.lineColor"
|
||||||
|
@change="
|
||||||
|
(val) => {
|
||||||
|
circleModel.lineColor = val;
|
||||||
|
onUpdate();
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</q-popup-proxy>
|
||||||
|
</q-icon>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
<q-input
|
||||||
|
outlined
|
||||||
|
v-model="circleModel.fillColor"
|
||||||
|
@change="onUpdate"
|
||||||
|
label="填充色"
|
||||||
|
lazy-rules
|
||||||
|
:rules="[(val) => (val && val.length > 0) || '线色不能为空']"
|
||||||
|
>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-icon name="colorize" class="cursor-pointer">
|
||||||
|
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
|
||||||
|
<q-color
|
||||||
|
v-model="circleModel.fillColor"
|
||||||
|
@change="
|
||||||
|
(val) => {
|
||||||
|
circleModel.fillColor = val;
|
||||||
|
onUpdate();
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</q-popup-proxy>
|
||||||
|
</q-icon>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
<q-input
|
||||||
|
outlined
|
||||||
|
v-model="circleModel.alpha"
|
||||||
|
mask="#.###"
|
||||||
|
@blur="onUpdate"
|
||||||
|
label="透明度"
|
||||||
|
lazy-rules
|
||||||
|
:rules="[
|
||||||
|
(val) => (val && val > 0 && val <= 1) || '透明度必须大于0且小于等于1',
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
<q-input
|
||||||
|
outlined
|
||||||
|
v-model.number="circleModel.radius"
|
||||||
|
type="number"
|
||||||
|
@blur="onUpdate"
|
||||||
|
label="圆半径"
|
||||||
|
lazy-rules
|
||||||
|
:rules="[(val) => val >= 0 || '圆半径必须大于等于0']"
|
||||||
|
/>
|
||||||
|
</q-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useFormData } from 'src/components/DrawAppFormUtils';
|
||||||
|
import { CircleData } from 'src/drawApp/graphics/CircleInteraction';
|
||||||
|
import { useDrawStore } from 'src/stores/draw-store';
|
||||||
|
|
||||||
|
const drawStore = useDrawStore();
|
||||||
|
const { data: circleModel, onUpdate } = useFormData(
|
||||||
|
new CircleData(),
|
||||||
|
drawStore.getDrawApp()
|
||||||
|
);
|
||||||
|
</script>
|
@ -37,7 +37,7 @@
|
|||||||
<q-input
|
<q-input
|
||||||
outlined
|
outlined
|
||||||
v-model="rectModel.fillColor"
|
v-model="rectModel.fillColor"
|
||||||
@blur="onUpdate"
|
@change="onUpdate"
|
||||||
label="填充色"
|
label="填充色"
|
||||||
lazy-rules
|
lazy-rules
|
||||||
:rules="[(val) => (val && val.length > 0) || '线色不能为空']"
|
:rules="[(val) => (val && val.length > 0) || '线色不能为空']"
|
||||||
|
@ -26,6 +26,9 @@ import { sync_data_message } from 'src/protos/sync_data_message';
|
|||||||
import { LineDraw } from 'src/graphics/line/LineDrawAssistant';
|
import { LineDraw } from 'src/graphics/line/LineDrawAssistant';
|
||||||
import { Line, LineTemplate } from 'src/graphics/line/Line';
|
import { Line, LineTemplate } from 'src/graphics/line/Line';
|
||||||
import { LineData } from './graphics/LineInteraction';
|
import { LineData } from './graphics/LineInteraction';
|
||||||
|
import { CircleDraw } from 'src/graphics/circle/CircleDrawAssistant';
|
||||||
|
import { Circle, CircleTemplate } from 'src/graphics/circle/Circle';
|
||||||
|
import { CircleData } from './graphics/CircleInteraction';
|
||||||
|
|
||||||
const UndoOptions: MenuItemOptions = {
|
const UndoOptions: MenuItemOptions = {
|
||||||
name: '撤销',
|
name: '撤销',
|
||||||
@ -54,6 +57,7 @@ export function initCommonDrawApp(app: IDrawApp) {
|
|||||||
new TextContentDraw(app, new TextContentTemplate(new IscsTextData()));
|
new TextContentDraw(app, new TextContentTemplate(new IscsTextData()));
|
||||||
new RectDraw(app, new RectTemplate(new RectData()));
|
new RectDraw(app, new RectTemplate(new RectData()));
|
||||||
new LineDraw(app, new LineTemplate(new LineData()));
|
new LineDraw(app, new LineTemplate(new LineData()));
|
||||||
|
new CircleDraw(app, new CircleTemplate(new CircleData()));
|
||||||
// 画布右键菜单
|
// 画布右键菜单
|
||||||
app.registerMenu(DefaultCanvasMenu);
|
app.registerMenu(DefaultCanvasMenu);
|
||||||
|
|
||||||
@ -83,6 +87,7 @@ interface ICommonStorage {
|
|||||||
texts: iscsGraphicData.Text[];
|
texts: iscsGraphicData.Text[];
|
||||||
rects: iscsGraphicData.Rect[];
|
rects: iscsGraphicData.Rect[];
|
||||||
lines: iscsGraphicData.Line[];
|
lines: iscsGraphicData.Line[];
|
||||||
|
circles: iscsGraphicData.Circle[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
export function loadCommonDrawDatas(storage: ICommonStorage): GraphicData[] {
|
export function loadCommonDrawDatas(storage: ICommonStorage): GraphicData[] {
|
||||||
@ -100,6 +105,9 @@ export function loadCommonDrawDatas(storage: ICommonStorage): GraphicData[] {
|
|||||||
storage.commonGraphicStorage.lines.forEach((line) => {
|
storage.commonGraphicStorage.lines.forEach((line) => {
|
||||||
datas.push(new LineData(line));
|
datas.push(new LineData(line));
|
||||||
});
|
});
|
||||||
|
storage.commonGraphicStorage.circles.forEach((circle) => {
|
||||||
|
datas.push(new CircleData(circle));
|
||||||
|
});
|
||||||
return datas;
|
return datas;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,13 +126,20 @@ export function saveCommonDrawDatas(app: IDrawApp, storage: ICommonStorage) {
|
|||||||
storage.commonGraphicStorage.arrows.push((arrowData as ArrowData).data);
|
storage.commonGraphicStorage.arrows.push((arrowData as ArrowData).data);
|
||||||
} else if (g instanceof TextContent) {
|
} else if (g instanceof TextContent) {
|
||||||
const textContentData = g.saveData();
|
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) {
|
} else if (g instanceof Rect) {
|
||||||
const rectData = g.saveData();
|
const rectData = g.saveData();
|
||||||
storage.commonGraphicStorage.rects.push((rectData as RectData).data);
|
storage.commonGraphicStorage.rects.push((rectData as RectData).data);
|
||||||
} else if (g instanceof Line) {
|
} else if (g instanceof Line) {
|
||||||
const lineData = g.saveData();
|
const lineData = g.saveData();
|
||||||
storage.commonGraphicStorage.lines.push((lineData as LineData).data);
|
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;
|
break;
|
||||||
case Arrow.Type:
|
case Arrow.Type:
|
||||||
const arrowData = iscsGraphicData.Arrow.deserialize(data.data);
|
const arrowData = iscsGraphicData.Arrow.deserialize(data.data);
|
||||||
syncNoEditData(operationType, arrowData, storage.commonGraphicStorage.arrows);
|
syncNoEditData(
|
||||||
|
operationType,
|
||||||
|
arrowData,
|
||||||
|
storage.commonGraphicStorage.arrows
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case TextContent.Type:
|
case TextContent.Type:
|
||||||
const iscsTextData = iscsGraphicData.Text.deserialize(data.data);
|
const iscsTextData = iscsGraphicData.Text.deserialize(data.data);
|
||||||
syncNoEditData(operationType, iscsTextData, storage.commonGraphicStorage.texts);
|
syncNoEditData(
|
||||||
|
operationType,
|
||||||
|
iscsTextData,
|
||||||
|
storage.commonGraphicStorage.texts
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
76
src/drawApp/graphics/CircleInteraction.ts
Normal file
76
src/drawApp/graphics/CircleInteraction.ts
Normal file
@ -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<iscsGraphicData.Circle>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
86
src/graphics/circle/Circle.ts
Normal file
86
src/graphics/circle/Circle.ts
Normal file
@ -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<ICircleData>();
|
||||||
|
}
|
||||||
|
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<Circle> {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
117
src/graphics/circle/CircleDrawAssistant.ts
Normal file
117
src/graphics/circle/CircleDrawAssistant.ts
Normal file
@ -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<Circle> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -110,14 +110,6 @@ export class LineDraw extends GraphicDrawAssistant<LineTemplate, ILineData> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onRightClick(): void {
|
|
||||||
if (this.points.length < 2) {
|
|
||||||
this.finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.createAndStore(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
onEsc(): void {
|
onEsc(): void {
|
||||||
if (this.points.length < 2) {
|
if (this.points.length < 2) {
|
||||||
this.finish();
|
this.finish();
|
||||||
|
@ -9,10 +9,6 @@ import {
|
|||||||
|
|
||||||
import { IRectData, Rect, RectTemplate } from './Rect';
|
import { IRectData, Rect, RectTemplate } from './Rect';
|
||||||
|
|
||||||
export interface IRectDrawOptions {
|
|
||||||
newData: () => IRectData;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RectDraw extends GraphicDrawAssistant<RectTemplate, IRectData> {
|
export class RectDraw extends GraphicDrawAssistant<RectTemplate, IRectData> {
|
||||||
point1: Point | null = null;
|
point1: Point | null = null;
|
||||||
point2: Point | null = null;
|
point2: Point | null = null;
|
||||||
@ -96,7 +92,7 @@ export class RectGraphicHitArea implements IHitArea {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class rectInteraction extends GraphicInteractionPlugin<Rect> {
|
export class rectInteraction extends GraphicInteractionPlugin<Rect> {
|
||||||
static Name = 'platform_transform';
|
static Name = 'rect_transform';
|
||||||
constructor(app: IDrawApp) {
|
constructor(app: IDrawApp) {
|
||||||
super(rectInteraction.Name, app);
|
super(rectInteraction.Name, app);
|
||||||
}
|
}
|
||||||
|
@ -262,6 +262,7 @@ import { Line } from 'src/graphics/line/Line';
|
|||||||
import { JlOperation } from 'jl-graphic';
|
import { JlOperation } from 'jl-graphic';
|
||||||
import { common } from 'src/protos/common';
|
import { common } from 'src/protos/common';
|
||||||
import { toStorageTransform } from 'src/drawApp/graphics/GraphicDataBase';
|
import { toStorageTransform } from 'src/drawApp/graphics/GraphicDataBase';
|
||||||
|
import { Circle } from 'src/graphics/circle/Circle';
|
||||||
|
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@ -336,6 +337,7 @@ function handleUtilsOption() {
|
|||||||
const drawAssistantsTypes = [
|
const drawAssistantsTypes = [
|
||||||
Arrow.Type,
|
Arrow.Type,
|
||||||
TextContent.Type,
|
TextContent.Type,
|
||||||
|
Circle.Type,
|
||||||
Rect.Type,
|
Rect.Type,
|
||||||
Line.Type,
|
Line.Type,
|
||||||
];
|
];
|
||||||
@ -356,6 +358,7 @@ function handleUtilsOption() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
drawDialogHeight.value = 0;
|
||||||
drawDialogHeight.value = 44 * Math.ceil(utilsOption.length / 2);
|
drawDialogHeight.value = 44 * Math.ceil(utilsOption.length / 2);
|
||||||
}
|
}
|
||||||
//左侧功能按钮
|
//左侧功能按钮
|
||||||
|
@ -216,9 +216,10 @@ export namespace iscsGraphicData {
|
|||||||
texts?: Text[];
|
texts?: Text[];
|
||||||
rects?: Rect[];
|
rects?: Rect[];
|
||||||
lines?: Line[];
|
lines?: Line[];
|
||||||
|
circles?: Circle[];
|
||||||
}) {
|
}) {
|
||||||
super();
|
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 (!Array.isArray(data) && typeof data == "object") {
|
||||||
if ("arrows" in data && data.arrows != undefined) {
|
if ("arrows" in data && data.arrows != undefined) {
|
||||||
this.arrows = data.arrows;
|
this.arrows = data.arrows;
|
||||||
@ -232,6 +233,9 @@ export namespace iscsGraphicData {
|
|||||||
if ("lines" in data && data.lines != undefined) {
|
if ("lines" in data && data.lines != undefined) {
|
||||||
this.lines = data.lines;
|
this.lines = data.lines;
|
||||||
}
|
}
|
||||||
|
if ("circles" in data && data.circles != undefined) {
|
||||||
|
this.circles = data.circles;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
get arrows() {
|
get arrows() {
|
||||||
@ -258,11 +262,18 @@ export namespace iscsGraphicData {
|
|||||||
set lines(value: Line[]) {
|
set lines(value: Line[]) {
|
||||||
pb_1.Message.setRepeatedWrapperField(this, 4, value);
|
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: {
|
static fromObject(data: {
|
||||||
arrows?: ReturnType<typeof Arrow.prototype.toObject>[];
|
arrows?: ReturnType<typeof Arrow.prototype.toObject>[];
|
||||||
texts?: ReturnType<typeof Text.prototype.toObject>[];
|
texts?: ReturnType<typeof Text.prototype.toObject>[];
|
||||||
rects?: ReturnType<typeof Rect.prototype.toObject>[];
|
rects?: ReturnType<typeof Rect.prototype.toObject>[];
|
||||||
lines?: ReturnType<typeof Line.prototype.toObject>[];
|
lines?: ReturnType<typeof Line.prototype.toObject>[];
|
||||||
|
circles?: ReturnType<typeof Circle.prototype.toObject>[];
|
||||||
}): CommonGraphicStorage {
|
}): CommonGraphicStorage {
|
||||||
const message = new CommonGraphicStorage({});
|
const message = new CommonGraphicStorage({});
|
||||||
if (data.arrows != null) {
|
if (data.arrows != null) {
|
||||||
@ -277,6 +288,9 @@ export namespace iscsGraphicData {
|
|||||||
if (data.lines != null) {
|
if (data.lines != null) {
|
||||||
message.lines = data.lines.map(item => Line.fromObject(item));
|
message.lines = data.lines.map(item => Line.fromObject(item));
|
||||||
}
|
}
|
||||||
|
if (data.circles != null) {
|
||||||
|
message.circles = data.circles.map(item => Circle.fromObject(item));
|
||||||
|
}
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
toObject() {
|
toObject() {
|
||||||
@ -285,6 +299,7 @@ export namespace iscsGraphicData {
|
|||||||
texts?: ReturnType<typeof Text.prototype.toObject>[];
|
texts?: ReturnType<typeof Text.prototype.toObject>[];
|
||||||
rects?: ReturnType<typeof Rect.prototype.toObject>[];
|
rects?: ReturnType<typeof Rect.prototype.toObject>[];
|
||||||
lines?: ReturnType<typeof Line.prototype.toObject>[];
|
lines?: ReturnType<typeof Line.prototype.toObject>[];
|
||||||
|
circles?: ReturnType<typeof Circle.prototype.toObject>[];
|
||||||
} = {};
|
} = {};
|
||||||
if (this.arrows != null) {
|
if (this.arrows != null) {
|
||||||
data.arrows = this.arrows.map((item: Arrow) => item.toObject());
|
data.arrows = this.arrows.map((item: Arrow) => item.toObject());
|
||||||
@ -298,6 +313,9 @@ export namespace iscsGraphicData {
|
|||||||
if (this.lines != null) {
|
if (this.lines != null) {
|
||||||
data.lines = this.lines.map((item: Line) => item.toObject());
|
data.lines = this.lines.map((item: Line) => item.toObject());
|
||||||
}
|
}
|
||||||
|
if (this.circles != null) {
|
||||||
|
data.circles = this.circles.map((item: Circle) => item.toObject());
|
||||||
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
serialize(): Uint8Array;
|
serialize(): Uint8Array;
|
||||||
@ -312,6 +330,8 @@ export namespace iscsGraphicData {
|
|||||||
writer.writeRepeatedMessage(3, this.rects, (item: Rect) => item.serialize(writer));
|
writer.writeRepeatedMessage(3, this.rects, (item: Rect) => item.serialize(writer));
|
||||||
if (this.lines.length)
|
if (this.lines.length)
|
||||||
writer.writeRepeatedMessage(4, this.lines, (item: Line) => item.serialize(writer));
|
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)
|
if (!w)
|
||||||
return writer.getResultBuffer();
|
return writer.getResultBuffer();
|
||||||
}
|
}
|
||||||
@ -333,6 +353,9 @@ export namespace iscsGraphicData {
|
|||||||
case 4:
|
case 4:
|
||||||
reader.readMessage(message.lines, () => pb_1.Message.addToRepeatedWrapperField(message, 4, Line.deserialize(reader), Line));
|
reader.readMessage(message.lines, () => pb_1.Message.addToRepeatedWrapperField(message, 4, Line.deserialize(reader), Line));
|
||||||
break;
|
break;
|
||||||
|
case 5:
|
||||||
|
reader.readMessage(message.circles, () => pb_1.Message.addToRepeatedWrapperField(message, 5, Circle.deserialize(reader), Circle));
|
||||||
|
break;
|
||||||
default: reader.skipField();
|
default: reader.skipField();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1111,6 +1134,240 @@ export namespace iscsGraphicData {
|
|||||||
return Line.deserialize(bytes);
|
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<typeof dependency_1.common.CommonInfo.prototype.toObject>;
|
||||||
|
code?: string;
|
||||||
|
position?: ReturnType<typeof dependency_1.common.Point.prototype.toObject>;
|
||||||
|
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<typeof dependency_1.common.CommonInfo.prototype.toObject>;
|
||||||
|
code?: string;
|
||||||
|
position?: ReturnType<typeof dependency_1.common.Point.prototype.toObject>;
|
||||||
|
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 {
|
export class CCTVButton extends pb_1.Message {
|
||||||
#one_of_decls: number[][] = [];
|
#one_of_decls: number[][] = [];
|
||||||
constructor(data?: any[] | {
|
constructor(data?: any[] | {
|
||||||
|
Loading…
Reference in New Issue
Block a user