This commit is contained in:
fan 2023-06-12 17:37:54 +08:00
commit 8be7941e5f
19 changed files with 3767 additions and 2624 deletions

View File

@ -51,6 +51,9 @@
<station-property
v-if="drawStore.selectedGraphicType === Station.Type"
></station-property>
<station-line-property
v-if="drawStore.selectedGraphicType === StationLine.Type"
></station-line-property>
<train-property
v-if="drawStore.selectedGraphicType === Train.Type"
></train-property>
@ -83,6 +86,7 @@ import LinkProperty from './properties/LinkProperty.vue';
import RectProperty from './properties/RectProperty.vue';
import PlatformProperty from './properties/PlatformProperty.vue';
import StationProperty from './properties/StationProperty.vue';
import StationLineProperty from './properties/StationLineProperty.vue';
import TrainProperty from './properties/TrainProperty.vue';
import IscsFanProperty from './properties/IscsFanProperty.vue';
import SignalProperty from './properties/SignalProperty.vue';
@ -92,6 +96,7 @@ import { Link } from 'src/graphics/link/Link';
import { Rect } from 'src/graphics/rect/Rect';
import { Platform } from 'src/graphics/platform/Platform';
import { Station } from 'src/graphics/station/Station';
import { StationLine } from 'src/graphics/stationLine/StationLine';
import { Train } from 'src/graphics/train/Train';
import { useDrawStore } from 'src/stores/draw-store';
import { IscsFan } from 'src/graphics/iscs-fan/IscsFan';

View File

@ -1,9 +1,9 @@
<template>
<q-form>
<q-input outlined readonly v-model="stationModel.id" label="id" hint="" />
<q-input outlined readonly v-model="rectModel.id" label="id" hint="" />
<q-input
outlined
v-model.number="stationModel.lineWidth"
v-model.number="rectModel.lineWidth"
type="number"
@blur="onUpdate"
label="线宽"
@ -13,7 +13,7 @@
<q-input
outlined
v-model="stationModel.lineColor"
v-model="rectModel.lineColor"
@blur="onUpdate"
label="线色"
lazy-rules
@ -23,10 +23,10 @@
<q-icon name="colorize" class="cursor-pointer">
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
<q-color
v-model="stationModel.lineColor"
v-model="rectModel.lineColor"
@change="
(val) => {
stationModel.lineColor = val;
rectModel.lineColor = val;
onUpdate();
}
"
@ -35,6 +35,33 @@
</q-icon>
</template>
</q-input>
<q-input
outlined
v-model.number="rectModel.width"
type="number"
@blur="onUpdate"
label="宽度"
lazy-rules
:rules="[(val) => (val && val > 0) || '宽度必须大于0']"
/>
<q-input
outlined
v-model.number="rectModel.height"
type="number"
@blur="onUpdate"
label="高度"
lazy-rules
:rules="[(val) => (val && val > 0) || '宽度必须大于0']"
/>
<q-input
outlined
v-model.number="rectModel.radius"
type="number"
@blur="onUpdate"
label="圆角半径"
lazy-rules
:rules="[(val) => (val && val > 0) || '圆角半径必须大于0']"
/>
</q-form>
</template>
@ -45,30 +72,29 @@ import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, watch } from 'vue';
const drawStore = useDrawStore();
const stationModel = reactive(new RectData());
const rectModel = reactive(new RectData());
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == Rect.Type) {
stationModel.copyFrom(val.saveData() as RectData);
rectModel.copyFrom(val.saveData() as RectData);
}
}
);
onMounted(() => {
const station = drawStore.selectedGraphic as Rect;
if (station) {
stationModel.copyFrom(station.saveData());
const Rect = drawStore.selectedGraphic as Rect;
if (Rect) {
rectModel.copyFrom(Rect.saveData());
}
});
function onUpdate() {
const station = drawStore.selectedGraphic as Rect;
if (station) {
drawStore.getDrawApp().updateGraphicAndRecord(station, stationModel);
const Rect = drawStore.selectedGraphic as Rect;
if (Rect) {
drawStore.getDrawApp().updateGraphicAndRecord(Rect, rectModel);
}
}
</script>

View File

@ -0,0 +1,80 @@
<template>
<q-form>
<q-input
outlined
readonly
v-model="stationLineModel.id"
label="id"
hint=""
/>
<q-input
outlined
label="车站名称"
@blur="onUpdate"
v-model="stationLineModel.code"
lazy-rules
/>
<q-select
outlined
@blur="onUpdate"
v-model="hasTransfer"
:options="optionsCircle"
label="是否有换乘"
/>
</q-form>
</template>
<script setup lang="ts">
import { StationLineData } from 'src/drawApp/graphics/StationLineInteraction';
import { StationLine } from 'src/graphics/stationLine/StationLine';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, ref, watch } from 'vue';
const drawStore = useDrawStore();
const stationLineModel = reactive(new StationLineData());
const hasTransfer = ref('是');
const optionsCircle = ['是', '否'];
enum showSelect {
= 'true',
= 'false',
}
enum showSelectData {
true = '是',
false = '否',
}
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == StationLine.Type) {
stationLineModel.copyFrom(val.saveData() as StationLineData);
hasTransfer.value = (showSelectData as never)[
stationLineModel.hasTransfer + ''
];
}
}
);
onMounted(() => {
const stationLine = drawStore.selectedGraphic as StationLine;
if (stationLine) {
stationLineModel.copyFrom(stationLine.saveData());
hasTransfer.value = (showSelectData as never)[
stationLineModel.hasTransfer + ''
];
}
});
function onUpdate() {
stationLineModel.hasTransfer = JSON.parse(
(showSelect as never)[hasTransfer.value]
);
const stationLine = drawStore.selectedGraphic as StationLine;
if (stationLine) {
drawStore
.getDrawApp()
.updateGraphicAndRecord(stationLine, stationLineModel);
}
}
</script>

View File

@ -7,3 +7,7 @@ export function saveJwtToken(token: string) {
export function getJwtToken(): string | null {
return sessionStorage.getItem(JwtTokenKey);
}
export function clearJwtToken(): void {
sessionStorage.removeItem(JwtTokenKey);
}

View File

@ -1,5 +1,6 @@
function getHost(): string {
// return '192.168.3.7:9081';
// return '192.168.3.47:9081';
return '192.168.3.233:9081';
}

View File

@ -57,13 +57,11 @@ export class RectData extends GraphicDataBase implements IRectData {
set height(v: number) {
this.data.height = v;
}
get points(): IPointData[] {
return this.data.points;
get radius(): number {
return this.data.radius;
}
set points(points: IPointData[]) {
this.data.points = points.map(
(p) => new graphicData.Point({ x: p.x, y: p.y })
);
set radius(v: number) {
this.data.radius = v;
}
clone(): RectData {
return new RectData(this.data.cloneMessage());

View File

@ -0,0 +1,45 @@
import * as pb_1 from 'google-protobuf';
import { GraphicDataBase } from './GraphicDataBase';
import { ISectionData } from 'src/graphics/section/Section';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { IPointData } from 'pixi.js';
export class SectionData extends GraphicDataBase implements ISectionData {
constructor(data?: graphicData.Section) {
let section;
if (!data) {
section = new graphicData.Section({
common: GraphicDataBase.defaultCommonInfo(),
});
} else {
section = data;
}
super(section);
}
public get data(): graphicData.Section {
return this.getData<graphicData.Section>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
get points(): IPointData[] {
return this.data.points;
}
set points(points: IPointData[]) {
this.data.points = points.map(
(p) => new graphicData.Point({ x: p.x, y: p.y })
);
}
clone(): SectionData {
return new SectionData(this.data.cloneMessage());
}
copyFrom(data: SectionData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: SectionData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}

View File

@ -0,0 +1,46 @@
import * as pb_1 from 'google-protobuf';
import { IStationLineData } from 'src/graphics/stationLine/StationLine';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
export class StationLineData
extends GraphicDataBase
implements IStationLineData
{
constructor(data?: graphicData.StationLine) {
let stationLine;
if (!data) {
stationLine = new graphicData.StationLine({
common: GraphicDataBase.defaultCommonInfo(),
});
} else {
stationLine = data;
}
super(stationLine);
}
public get data(): graphicData.StationLine {
return this.getData<graphicData.StationLine>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
get hasTransfer(): boolean {
return this.data.hasTransfer;
}
set hasTransfer(v: boolean) {
this.data.hasTransfer = v;
}
clone(): StationLineData {
return new StationLineData(this.data.cloneMessage());
}
copyFrom(data: StationLineData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: StationLineData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}

View File

@ -3,13 +3,7 @@ import { IPointData, Point } from 'pixi.js';
import { IscsFan } from 'src/graphics/iscs-fan/IscsFan';
import { Link } from 'src/graphics/link/Link';
import { LinkDraw } from 'src/graphics/link/LinkDrawAssistant';
import { Rect } from 'src/graphics/rect/Rect';
import { RectDraw } from 'src/graphics/rect/RectDrawAssistant';
import { Platform } from 'src/graphics/platform/Platform';
import { PlatformDraw } from 'src/graphics/platform/PlatformDrawAssistant';
import { Station } from 'src/graphics/station/Station';
import { Train } from 'src/graphics/train/Train';
import { StationDraw } from 'src/graphics/station/StationDrawAssistant';
import { TrainDraw } from 'src/graphics/train/TrainDrawAssistant';
import { Signal } from 'src/graphics/signal/Signal';
import { SignalDraw } from 'src/graphics/signal/SignalDrawAssistant';
@ -25,12 +19,21 @@ import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { IscsFanData } from './graphics/IscsFanInteraction';
import { LinkData } from './graphics/LinkInteraction';
import { RectData } from './graphics/RectInteraction';
import { PlatformData } from './graphics/PlatformInteraction';
import { StationData } from './graphics/StationInteraction';
import { TrainData } from './graphics/TrainInteraction';
import { SignalData } from './graphics/SignalInteraction';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { Rect } from 'src/graphics/rect/Rect';
import { RectDraw } from 'src/graphics/rect/RectDrawAssistant';
import { RectData } from './graphics/RectInteraction';
import { Platform } from 'src/graphics/platform/Platform';
import { PlatformData } from './graphics/PlatformInteraction';
import { PlatformDraw } from 'src/graphics/platform/PlatformDrawAssistant';
import { Station } from 'src/graphics/station/Station';
import { StationDraw } from 'src/graphics/station/StationDrawAssistant';
import { StationData } from './graphics/StationInteraction';
import { StationLine } from 'src/graphics/stationLine/StationLine';
import { StationLineDraw } from 'src/graphics/stationLine/StationLineDrawAssistant';
import { StationLineData } from './graphics/StationLineInteraction';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { TurnoutDraw } from 'src/graphics/turnout/TurnoutDrawAssistant';
import { TurnoutData } from './graphics/TurnoutInteraction';
@ -40,6 +43,9 @@ import { RunLineData } from './graphics/RunLineInteraction';
import { saveDraft, getDraft } from 'src/api/DraftApi';
import { useDrawStore } from 'src/stores/draw-store';
import { successNotify, errorNotify } from '../utils/CommonNotify';
import { Section } from 'src/graphics/section/Section';
import { SectionDraw } from 'src/graphics/section/SectionDrawAssistant';
import { SectionData } from './graphics/SectionInteraction';
export function fromStoragePoint(p: graphicData.Point): Point {
return new Point(p.x, p.y);
@ -117,6 +123,9 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
| SignalDraw
| TurnoutDraw
| RunLineDraw
| SectionDraw
| StationLineDraw
| RectDraw
)[] = [];
if (draftType === 'Line') {
drawAssistants = [
@ -138,61 +147,28 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
// new TrainDraw(app, () => {
// return new TrainData();
// }),
new SectionDraw(app, () => new SectionData()),
];
} else {
drawAssistants = [
new StationLineDraw(app, () => {
return new StationLineData();
}),
new RectDraw(app, () => {
return new RectData();
}),
];
app.addKeyboardListener(
new KeyListener({
value: 'KeyP',
value: 'KeyI',
onPress: () => {
app.interactionPlugin(Platform.Type).resume();
app.interactionPlugin(StationLine.Type).resume();
},
})
);
app.addKeyboardListener(
new KeyListener({
value: 'KeyT',
onPress: () => {
console.log(app.interactionPlugin(Turnout.Type));
app.interactionPlugin(Turnout.Type).resume();
},
})
);
app.addKeyboardListener(
new KeyListener({
value: 'KeyO',
onPress: () => {
app.interactionPlugin(Station.Type).resume();
},
})
);
app.addKeyboardListener(
new KeyListener({
value: 'KeyH',
onPress: () => {
app.interactionPlugin(Signal.Type).resume();
},
})
);
app.addKeyboardListener(
new KeyListener({
value: 'KeyR',
onPress: () => {
app.interactionPlugin(RunLine.Type).resume();
},
})
);
// app.addKeyboardListener(
// new KeyListener({
// value: 'KeyR',
// onPress: () => {
// app.interactionPlugin(Train.Type).resume();
// },
// })
// );
}
app.setOptions({
drawAssistants: drawAssistants,
});
app.setOptions({ drawAssistants: drawAssistants });
// 画布右键菜单
app.registerMenu(DefaultCanvasMenu);
@ -255,7 +231,7 @@ export function saveDrawDatas(app: JlDrawApp) {
storage.links.push((linkData as LinkData).data);
} else if (Rect.Type === g.type) {
const rectData = (g as Rect).saveData();
storage.Rects.push((rectData as RectData).data);
storage.rects.push((rectData as RectData).data);
} else if (IscsFan.Type === g.type) {
const IscsFanData = (g as IscsFan).saveData();
storage.iscsFans.push((IscsFanData as IscsFanData).data);
@ -277,6 +253,12 @@ export function saveDrawDatas(app: JlDrawApp) {
} else if (RunLine.Type === g.type) {
const runLineData = (g as RunLine).saveData();
storage.runLines.push((runLineData as RunLineData).data);
} else if (Section.Type === g.type) {
const sectionData = (g as Section).saveData();
storage.section.push((sectionData as SectionData).data);
} else if (StationLine.Type === g.type) {
const stationLineData = (g as StationLine).saveData();
storage.stationLines.push((stationLineData as StationLineData).data);
}
});
const base64 = fromUint8Array(storage.serialize());
@ -305,7 +287,7 @@ export async function loadDrawDatas(app: GraphicApp) {
storage.links.forEach((link) => {
datas.push(new LinkData(link));
});
storage.Rects.forEach((rect) => {
storage.rects.forEach((rect) => {
datas.push(new RectData(rect));
});
storage.iscsFans.forEach((fan) => {
@ -329,6 +311,12 @@ export async function loadDrawDatas(app: GraphicApp) {
storage.runLines.forEach((runLine) => {
datas.push(new RunLineData(runLine));
});
storage.section.forEach((section) => {
datas.push(new SectionData(section));
});
storage.stationLines.forEach((stationLine) => {
datas.push(new StationLineData(stationLine));
});
app.loadGraphic(datas);
} else {
app.loadGraphic([]);

View File

@ -1,5 +1,10 @@
import { Color, Graphics, IPointData, Point } from 'pixi.js';
import { GraphicData, JlGraphic, JlGraphicTemplate } from 'src/jl-graphic';
import { Color, Graphics, IPointData, Point, Rectangle } from 'pixi.js';
import {
GraphicData,
JlGraphic,
JlGraphicTemplate,
getRectangleCenter,
} from 'src/jl-graphic';
export interface IRectData extends GraphicData {
get code(): string; // 编号
@ -14,8 +19,8 @@ export interface IRectData extends GraphicData {
set width(v: number);
get height(): number; // 高度
set height(v: number);
get points(): IPointData[]; // 线坐标点
set points(points: IPointData[]);
get radius(): number; // 圆角半径
set radius(v: number);
clone(): IRectData;
copyFrom(data: IRectData): void;
eq(other: IRectData): boolean;
@ -24,16 +29,13 @@ export interface IRectData extends GraphicData {
const rectConsts = {
lineWidth: 2,
lineColor: '0xff0000',
width: 60,
height: 20,
};
export class Rect extends JlGraphic {
static Type = 'Rect';
rectGraphic: Graphics;
rectGraphic: Graphics = new Graphics();
constructor() {
super(Rect.Type);
this.rectGraphic = new Graphics();
this.addChild(this.rectGraphic);
}
@ -41,44 +43,53 @@ export class Rect extends JlGraphic {
return this.getDatas<IRectData>();
}
doRepaint(): void {
const width = this.datas.width;
const height = this.datas.height;
if (this.linePoints.length == 0) {
const r1 = new Point(this.datas.point.x, this.datas.point.y);
const r2 = new Point(r1.x + width, r1.y);
const r3 = new Point(r1.x + width, r1.y + height);
const r4 = new Point(r1.x, r1.y + height);
this.datas.points = [r1, r2, r3, r4, r1];
}
const rectGraphic = this.rectGraphic;
rectGraphic.clear();
rectGraphic.lineStyle(
this.datas.lineWidth,
new Color(this.datas.lineColor)
);
rectGraphic.drawPolygon(this.datas.points);
const radius = this.datas?.radius || 0;
rectGraphic.drawRoundedRect(
0,
0,
this.datas.width,
this.datas.height,
radius
);
rectGraphic.pivot = getRectangleCenter(
new Rectangle(0, 0, this.datas.width, this.datas.height)
);
const transformPos = this.datas.transform.position;
if (transformPos.x == 0 && transformPos.y == 0) {
this.position.set(
this.datas.point.x + this.datas.width / 2,
this.datas.point.y + this.datas.height / 2
);
} else {
this.position.set(
this.datas.transform.position.x,
this.datas.transform.position.y
);
}
}
get linePoints(): IPointData[] {
return this.datas.points;
}
set linePoints(points: IPointData[]) {
const old = this.datas.clone();
old.points = points;
this.updateData(old);
rectPoints(): IPointData[] {
const r1 = new Point(this.datas.point.x, this.datas.point.y);
const r2 = new Point(r1.x + this.datas.width, r1.y);
const r3 = new Point(r1.x + this.datas.width, r1.y + this.datas.height);
const r4 = new Point(r1.x, r1.y + this.datas.height);
const rectPoints = [r1, r2, r3, r4, r1];
return rectPoints;
}
}
export class RectTemplate extends JlGraphicTemplate<Rect> {
lineWidth: number;
lineColor: string;
width: number;
height: number;
constructor() {
super(Rect.Type);
this.lineWidth = rectConsts.lineWidth;
this.lineColor = rectConsts.lineColor;
this.width = rectConsts.width;
this.height = rectConsts.height;
}
new(): Rect {
return new Rect();

View File

@ -1,38 +1,13 @@
import { FederatedPointerEvent, Graphics, Point, IHitArea } from 'pixi.js';
import {
FederatedPointerEvent,
Graphics,
Point,
IHitArea,
DisplayObject,
FederatedMouseEvent,
} from 'pixi.js';
import {
DraggablePoint,
GraphicApp,
GraphicDrawAssistant,
GraphicInteractionPlugin,
GraphicTransformEvent,
JlDrawApp,
JlGraphic,
linePoint,
} from 'src/jl-graphic';
import AbsorbablePoint, {
AbsorbablePosition,
} from 'src/jl-graphic/graphic/AbsorbablePosition';
import {
ILineGraphic,
PolylineEditPlugin,
addWaySegmentingConfig,
addPolygonSegmentingPoint,
clearWayPoint,
clearWaypointsConfig,
getWayLineIndex,
} from 'src/jl-graphic/plugins/GraphicEditPlugin';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { IRectData, Rect, RectTemplate } from './Rect';
import { Link } from '../link/Link';
export interface IRectDrawOptions {
newData: () => IRectData;
@ -46,7 +21,7 @@ export class RectDraw extends GraphicDrawAssistant<RectTemplate, IRectData> {
constructor(app: JlDrawApp, createData: () => IRectData) {
super(app, new RectTemplate(), createData, 'sym_o_square', '矩形Rect');
this.container.addChild(this.rectGraphic);
RectPointsEditPlugin.init(app);
rectInteraction.init(app);
}
bind(): void {
@ -90,10 +65,6 @@ export class RectDraw extends GraphicDrawAssistant<RectTemplate, IRectData> {
return [x, y, w, h];
}
prepareData(data: IRectData): boolean {
if (this.point1 == null) {
console.log('Rect绘制因点不够取消绘制');
return false;
}
const p1 = this.point1 as Point;
const p2 = this.point2 as Point;
const [x, y, width, height] = this.normalize(p1, p2);
@ -115,147 +86,42 @@ export class RectGraphicHitArea implements IHitArea {
}
contains(x: number, y: number): boolean {
let contains = false;
const datas = this.rect.datas;
const tolerance = datas.lineWidth;
const p1 = new Point(0, 0);
const p2 = new Point(p1.x + datas.width, p1.y);
const p3 = new Point(p1.x + datas.width, p1.y + datas.height);
const p4 = new Point(p1.x, p1.y + datas.height);
const p = new Point(x, y);
const rectData = this.rect.datas;
//contains = pointPolygon(p, rectData.points, rectData.lineWidth);是否包含多边形内部
const tolerance = rectData.lineWidth;
for (let i = 0; i < rectData.points.length - 1; i++) {
const p1 = rectData.points[i];
const p2 = rectData.points[i + 1];
contains = contains || linePoint(p1, p2, p, tolerance);
if (contains) {
break;
}
}
contains = contains || linePoint(p1, p2, p, tolerance);
contains = contains || linePoint(p2, p3, p, tolerance);
contains = contains || linePoint(p3, p4, p, tolerance);
contains = contains || linePoint(p4, p1, p, tolerance);
return contains;
}
}
/**
*
* @param rect
* @returns
*/
function buildAbsorbablePositions(rect: Rect): AbsorbablePosition[] {
const aps: AbsorbablePosition[] = [];
const rects = rect.queryStore.queryByType<Rect>(Rect.Type);
const links = rect.queryStore.queryByType<Link>(Link.Type);
links.forEach((other) => {
const apa = new AbsorbablePoint(
other.localToCanvasPoint(other.getStartPoint())
);
const apb = new AbsorbablePoint(
other.localToCanvasPoint(other.getEndPoint())
);
aps.push(apa, apb);
});
rects.forEach((other) => {
if (other.id == rect.id) {
return;
}
other.linePoints.forEach((point) => {
const absorbablePoint = new AbsorbablePoint(
other.localToCanvasPoint(point)
);
aps.push(absorbablePoint);
});
});
return aps;
}
/**
*
* @param g
* @param dp
* @param index
*/
function onEditPointCreate(g: ILineGraphic, dp: DraggablePoint): void {
const rect = g as Rect;
// 端点
dp.on('transformstart', (e: GraphicTransformEvent) => {
if (e.isShift()) {
rect.getGraphicApp().setOptions({
absorbablePositions: buildAbsorbablePositions(rect),
});
}
});
}
const RectEditMenu: ContextMenu = ContextMenu.init({
name: '矩形编辑菜单',
groups: [
{
items: [addWaySegmentingConfig, clearWaypointsConfig],
},
],
});
/**
* rect路径编辑
*/
export class RectPointsEditPlugin extends GraphicInteractionPlugin<Rect> {
static Name = 'RectPointsDrag';
constructor(app: GraphicApp) {
super(RectPointsEditPlugin.Name, app);
app.registerMenu(RectEditMenu);
export class rectInteraction extends GraphicInteractionPlugin<Rect> {
static Name = 'platform_transform';
constructor(app: JlDrawApp) {
super(rectInteraction.Name, app);
}
static init(app: GraphicApp): RectPointsEditPlugin {
return new RectPointsEditPlugin(app);
static init(app: JlDrawApp) {
return new rectInteraction(app);
}
filter(...grahpics: JlGraphic[]): Rect[] | undefined {
return grahpics.filter((g) => g.type == Rect.Type) as Rect[];
return grahpics.filter((g) => g.type === Rect.Type).map((g) => g as Rect);
}
bind(g: Rect): void {
g.rectGraphic.eventMode = 'static';
g.rectGraphic.cursor = 'pointer';
g.eventMode = 'static';
g.cursor = 'pointer';
g.scalable = true;
g.rotatable = true;
g.rectGraphic.hitArea = new RectGraphicHitArea(g);
g.on('_rightclick', this.onContextMenu, this);
g.on('selected', this.onSelected, this);
g.on('unselected', this.onUnselected, this);
}
unbind(g: Rect): void {
g.off('_rightclick', this.onContextMenu, this);
g.off('selected', this.onSelected, this);
g.off('unselected', this.onUnselected, this);
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const rect = target.getGraphic() as Rect;
this.app.updateSelected(rect);
addWaySegmentingConfig.handler = () => {
const linePoints = rect.linePoints;
const p = rect.screenToLocalPoint(e.global);
const { start, end } = getWayLineIndex(linePoints, p);
addPolygonSegmentingPoint(rect, start, end);
};
clearWaypointsConfig.handler = () => {
clearWayPoint(rect, false);
};
RectEditMenu.open(e.global);
}
onSelected(g: DisplayObject): void {
const rect = g as Rect;
let lep = rect.getAssistantAppend<PolylineEditPlugin>(
PolylineEditPlugin.Name
);
if (!lep) {
lep = new PolylineEditPlugin(rect, { onEditPointCreate });
rect.addAssistantAppend(lep);
}
lep.showAll();
}
onUnselected(g: DisplayObject): void {
const rect = g as Rect;
const lep = rect.getAssistantAppend<PolylineEditPlugin>(
PolylineEditPlugin.Name
);
if (lep) {
lep.hideAll();
}
g.eventMode = 'none';
g.scalable = false;
g.rotatable = false;
}
}

View File

@ -0,0 +1,76 @@
import { Graphics, IPointData } from 'pixi.js';
import { GraphicData, JlGraphic, JlGraphicTemplate } from 'src/jl-graphic';
import { ILineGraphic } from 'src/jl-graphic/plugins/GraphicEditPlugin';
import { Link } from '../link/Link';
export interface ISectionData extends GraphicData {
get code(): string; // 编号
set code(v: string);
get points(): IPointData[]; // 线坐标点
set points(points: IPointData[]);
clone(): ISectionData;
copyFrom(data: ISectionData): void;
eq(other: ISectionData): boolean;
}
export const SectionConsts = {
lineColor: '#5578b6',
lineWidth: 5,
};
export class Section extends JlGraphic implements ILineGraphic {
static Type = 'Section';
lineGraphic: Graphics;
constructor() {
super(Section.Type);
this.lineGraphic = new Graphics();
this.addChild(this.lineGraphic);
}
doRepaint() {
if (this.datas.points.length < 2) {
throw new Error('Link坐标数据异常');
}
this.lineGraphic.clear();
this.lineGraphic.lineStyle(
SectionConsts.lineWidth,
SectionConsts.lineColor
);
this.datas.points.forEach((p, i) => {
if (i !== 0) {
this.lineGraphic.lineTo(p.x, p.y);
} else {
this.lineGraphic.moveTo(p.x, p.y);
}
});
}
getStartPoint() {
return this.datas.points[0];
}
getEndPoint(): IPointData {
return this.datas.points[this.datas.points.length - 1];
}
get datas(): ISectionData {
return this.getDatas<ISectionData>();
}
get linePoints(): IPointData[] {
return this.datas.points;
}
set linePoints(points: IPointData[]) {
const old = this.datas.clone();
old.points = points;
this.updateData(old);
}
}
export class SectionTemplate extends JlGraphicTemplate<Section> {
constructor() {
super(Section.Type);
}
new() {
return new Section();
}
}

View File

@ -0,0 +1,193 @@
import {
DraggablePoint,
GraphicApp,
GraphicDrawAssistant,
GraphicInteractionPlugin,
GraphicTransformEvent,
JlDrawApp,
JlGraphic,
linePoint,
} from 'src/jl-graphic';
import {
ISectionData,
Section,
SectionConsts,
SectionTemplate,
} from './Section';
import {
DisplayObject,
FederatedMouseEvent,
Graphics,
IHitArea,
Point,
} from 'pixi.js';
import {
ILineGraphic,
PolylineEditPlugin,
} from 'src/jl-graphic/plugins/GraphicEditPlugin';
import AbsorbablePoint, {
AbsorbablePosition,
} from 'src/jl-graphic/graphic/AbsorbablePosition';
import { Turnout } from '../turnout/Turnout';
export class SectionDraw extends GraphicDrawAssistant<
SectionTemplate,
ISectionData
> {
points: Point[] = [];
graphic = new Graphics();
constructor(app: JlDrawApp, createData: () => ISectionData) {
super(
app,
new SectionTemplate(),
createData,
'sym_o_timeline',
'区段Section'
);
this.container.addChild(this.graphic);
SectionPointEditPlugin.init(app);
}
onLeftDown(e: FederatedMouseEvent): void {
const { x, y } = this.toCanvasCoordinates(e.global);
const p = new Point(x, y);
// this.points.pop();
this.points.push(p);
}
onRightClick(): void {
this.createAndStore(true);
}
redraw(cp: Point): void {
if (this.points.length < 1) return;
this.graphic.clear();
this.graphic.lineStyle(SectionConsts.lineWidth, SectionConsts.lineColor);
// this.points.push(cp);
this.points.forEach((p, i) => {
if (i !== 0) {
this.graphic.lineTo(p.x, p.y);
} else {
this.graphic.moveTo(p.x, p.y);
}
});
this.graphic.lineTo(cp.x, cp.y);
}
prepareData(data: ISectionData): boolean {
data.points = this.points;
return true;
}
clearCache(): void {
this.points = [];
this.graphic.clear();
}
}
class SectionGraphicHitArea implements IHitArea {
section: Section;
constructor(section: Section) {
this.section = section;
}
contains(x: number, y: number): boolean {
for (let i = 1; i < this.section.datas.points.length; i++) {
const p1 = this.section.datas.points[i - 1];
const p2 = this.section.datas.points[i];
if (linePoint(p1, p2, { x, y }, SectionConsts.lineWidth)) {
return true;
}
}
return false;
}
}
function buildAbsorbablePositions(section: Section): AbsorbablePosition[] {
const aps: AbsorbablePosition[] = [];
const sections = section.queryStore.queryByType<Section>(Section.Type);
sections.forEach((other) => {
if (other.id == section.id) {
return;
}
const apa = new AbsorbablePoint(
other.localToCanvasPoint(other.getStartPoint())
);
const apb = new AbsorbablePoint(
other.localToCanvasPoint(other.getEndPoint())
);
aps.push(apa, apb);
});
const turnouts = section.queryStore.queryByType<Turnout>(Turnout.Type);
turnouts.forEach((turnout) => {
turnout.localToCanvasPoints(...turnout.getPortPoints()).forEach((p) => {
aps.push(new AbsorbablePoint(p));
});
});
return aps;
}
function onEditPointCreate(
g: ILineGraphic,
dp: DraggablePoint,
index: number
): void {
const section = g as Section;
if (index === 0 || index == section.datas.points.length - 1) {
// 端点
dp.on('transformstart', (e: GraphicTransformEvent) => {
if (e.isShift()) {
section.getGraphicApp().setOptions({
absorbablePositions: buildAbsorbablePositions(section),
});
}
});
}
}
export class SectionPointEditPlugin extends GraphicInteractionPlugin<Section> {
static Name = 'SectionPointDrag';
constructor(app: GraphicApp) {
super(SectionPointEditPlugin.Name, app);
}
static init(app: GraphicApp) {
return new SectionPointEditPlugin(app);
}
filter(...grahpics: JlGraphic[]): Section[] | undefined {
return grahpics.filter((g) => g.type == Section.Type) as Section[];
}
bind(g: Section): void {
g.lineGraphic.eventMode = 'static';
g.lineGraphic.cursor = 'pointer';
g.lineGraphic.hitArea = new SectionGraphicHitArea(g);
g.on('selected', this.onSelected, this);
g.on('unselected', this.onUnselected, this);
}
unbind(g: Section): void {
g.off('selected', this.onSelected, this);
g.off('unselected', this.onUnselected, this);
}
onSelected(g: DisplayObject): void {
const section = g as Section;
let lep = section.getAssistantAppend<PolylineEditPlugin>(
PolylineEditPlugin.Name
);
if (!lep) {
lep = new PolylineEditPlugin(section, { onEditPointCreate });
section.addAssistantAppend(lep);
}
lep.showAll();
}
onUnselected(g: DisplayObject): void {
const section = g as Section;
const lep = section.getAssistantAppend<PolylineEditPlugin>(
PolylineEditPlugin.Name
);
if (lep) {
lep.hideAll();
}
}
}

View File

@ -0,0 +1,140 @@
import { Color, Container, Graphics, Point } from 'pixi.js';
import {
GraphicData,
JlGraphic,
JlGraphicTemplate,
VectorText,
} from 'src/jl-graphic';
export interface IStationLineData extends GraphicData {
get code(): string; // 编号
set code(v: string);
get hasTransfer(): boolean;
set hasTransfer(v: boolean);
clone(): IStationLineData;
copyFrom(data: IStationLineData): void;
eq(other: IStationLineData): boolean;
}
const stationConsts = {
radius: 5,
borderWidth: 1,
borderColor: '0xff0000',
fillColor: '0xff0000',
circleOffsetY: -20,
transferRadius: 3.5,
transferWidth: 0.2,
transferColor: '0x0fe81f',
codeColor: '0xF48815',
codeFontSize: 22,
lineWidth: 3,
};
//子元素--圆点
class circleGraphic extends Container {
circle: Graphics = new Graphics();
arcUp: Graphics = new Graphics();
arcDown: Graphics = new Graphics();
arrowUp: Graphics = new Graphics();
arrowDown: Graphics = new Graphics();
constructor() {
super();
this.addChild(this.circle);
this.addChild(this.arcUp);
this.addChild(this.arcDown);
this.addChild(this.arrowUp);
this.addChild(this.arrowDown);
}
draw(datas: IStationLineData): void {
const circle = this.circle;
circle.clear();
circle.lineStyle(
stationConsts.borderWidth,
new Color(stationConsts.borderColor)
);
circle.beginFill(stationConsts.fillColor, 1);
circle.drawCircle(0, 0, stationConsts.radius);
circle.endFill;
circle.position.set(0, stationConsts.circleOffsetY);
const arcGraphicUp = this.arcUp;
const arcGraphicDown = this.arcDown;
const arrowUpGraphic = this.arrowUp;
const arrowDownGraphic = this.arrowDown;
arcGraphicUp.clear();
arcGraphicDown.clear();
arrowUpGraphic.clear();
arrowDownGraphic.clear();
if (datas.hasTransfer) {
this.drawTransfer(arcGraphicUp, arrowUpGraphic);
this.drawTransfer(arcGraphicDown, arrowDownGraphic);
arcGraphicDown.rotation = Math.PI;
arrowDownGraphic.rotation = Math.PI - (Math.PI * 1) / 25;
arrowDownGraphic.position.set(
stationConsts.transferRadius,
stationConsts.circleOffsetY
);
}
}
drawTransfer(transferGraphic: Graphics, arrowGraphic: Graphics): void {
transferGraphic.lineStyle(
stationConsts.transferWidth,
new Color(stationConsts.transferColor)
);
transferGraphic.arc(
0,
0,
stationConsts.transferRadius,
Math.PI / 10,
Math.PI,
false
);
transferGraphic.position.set(0, stationConsts.circleOffsetY);
arrowGraphic.lineStyle(
stationConsts.transferWidth,
new Color(stationConsts.transferColor)
);
arrowGraphic.moveTo(0, 0);
arrowGraphic.lineTo(1, 1);
arrowGraphic.moveTo(0, 0);
arrowGraphic.lineTo(-1, 1);
arrowGraphic.position.set(
-stationConsts.transferRadius,
stationConsts.circleOffsetY
);
arrowGraphic.pivot = new Point(0, 0);
arrowGraphic.rotation = -(Math.PI * 1) / 25;
}
}
export class StationLine extends JlGraphic {
static Type = 'stationLine';
codeGraph: VectorText = new VectorText(''); //车站名
circleGraphic: circleGraphic = new circleGraphic();
constructor() {
super(StationLine.Type);
this.addChild(this.codeGraph);
this.addChild(this.circleGraphic);
this.circleGraphic.name = 'circle';
}
get datas(): IStationLineData {
return this.getDatas<IStationLineData>();
}
doRepaint(): void {
const codeGraph = this.codeGraph;
codeGraph.text = this.datas?.code || '车站StationLine';
codeGraph.style.fill = stationConsts.codeColor;
codeGraph.setVectorFontSize(stationConsts.codeFontSize);
codeGraph.anchor.set(0.5);
this.circleGraphic.draw(this.datas);
}
}
export class StationLineTemplate extends JlGraphicTemplate<StationLine> {
hasTransfer: boolean;
constructor() {
super(StationLine.Type);
this.hasTransfer = true;
}
new(): StationLine {
return new StationLine();
}
}

View File

@ -0,0 +1,100 @@
import { FederatedPointerEvent, Point } from 'pixi.js';
import {
GraphicData,
GraphicDrawAssistant,
GraphicInteractionPlugin,
JlDrawApp,
JlGraphic,
} from 'src/jl-graphic';
import {
IStationLineData,
StationLine,
StationLineTemplate,
} from './StationLine';
export interface IStationLineDrawOptions {
newData: () => IStationLineData;
}
export class StationLineDraw extends GraphicDrawAssistant<
StationLineTemplate,
IStationLineData
> {
codeGraph: StationLine;
constructor(app: JlDrawApp, createData: () => IStationLineData) {
super(
app,
new StationLineTemplate(),
createData,
'svguse:/drawIcon.svg#icon-station',
'车站StationLine'
);
this.codeGraph = this.graphicTemplate.new();
this.container.addChild(this.codeGraph);
stationLineInteraction.init(app);
}
bind(): void {
super.bind();
const data = { graphicType: 'stationLine' } as GraphicData;
this.codeGraph.loadData(data);
this.codeGraph.doRepaint();
}
unbind(): void {
super.unbind();
}
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: IStationLineData): boolean {
const template = this.graphicTemplate;
data.transform = this.container.saveTransform();
data.hasTransfer = template.hasTransfer;
return true;
}
}
export class stationLineInteraction extends GraphicInteractionPlugin<StationLine> {
static Name = 'stationLine_transform';
constructor(app: JlDrawApp) {
super(stationLineInteraction.Name, app);
}
static init(app: JlDrawApp) {
return new stationLineInteraction(app);
}
filter(...grahpics: JlGraphic[]): StationLine[] | undefined {
return grahpics
.filter((g) => g.type === StationLine.Type)
.map((g) => g as StationLine);
}
bind(g: StationLine): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.scalable = true;
g.rotatable = true;
g.circleGraphic.eventMode = 'static';
g.circleGraphic.cursor = 'pointer';
g.circleGraphic.draggable = true;
g.circleGraphic.selectable = true;
g.circleGraphic.transformSave = true;
}
unbind(g: StationLine): void {
g.eventMode = 'none';
g.scalable = false;
g.rotatable = false;
g.circleGraphic.eventMode = 'none';
g.circleGraphic.draggable = false;
g.circleGraphic.selectable = false;
g.circleGraphic.transformSave = false;
}
}

View File

@ -104,6 +104,10 @@ export class Turnout extends JlGraphic {
return this.getStates<ITurnoutState>();
}
getPortPoints() {
return [this.datas.pointA, this.datas.pointB, this.datas.pointC];
}
doRepaint(): void {
const { pointA, pointB, pointC } = this.datas;

View File

@ -1,4 +1,5 @@
import {
AbsorbablePosition,
DraggablePoint,
GraphicApp,
GraphicDrawAssistant,
@ -25,6 +26,8 @@ import {
} from 'pixi.js';
import { GraphicEditPlugin } from 'src/jl-graphic/plugins/GraphicEditPlugin';
import Vector2 from 'src/jl-graphic/math/Vector2';
import { Section } from '../section/Section';
import AbsorbablePoint from 'src/jl-graphic/graphic/AbsorbablePosition';
export class TurnoutDraw extends GraphicDrawAssistant<
TurnoutTemplate,
@ -94,6 +97,41 @@ export class TurnoutHitArea implements IHitArea {
}
}
function buildAbsorbablePositions(turnout: Turnout): AbsorbablePosition[] {
const aps: AbsorbablePosition[] = [];
const sections = turnout.queryStore.queryByType<Section>(Section.Type);
sections.forEach((section) => {
const ps = new AbsorbablePoint(
section.localToCanvasPoint(section.getStartPoint())
);
const pe = new AbsorbablePoint(
section.localToCanvasPoint(section.getEndPoint())
);
aps.push(ps, pe);
});
const turnouts = turnout.queryStore.queryByType<Turnout>(Turnout.Type);
turnouts.forEach((otherTurnout) => {
if (turnout.id === otherTurnout.id) return;
otherTurnout.getPortPoints().forEach((portPoint) => {
aps.push(new AbsorbablePoint(otherTurnout.localToCanvasPoint(portPoint)));
});
});
return aps;
}
function onEditPointCreate(turnout: Turnout, dp: DraggablePoint) {
dp.on('transformstart', (e: GraphicTransformEvent) => {
if (e.isShift()) {
turnout.getGraphicApp().setOptions({
absorbablePositions: buildAbsorbablePositions(turnout),
});
}
});
}
export class TurnoutPointsInteractionPlugin extends GraphicInteractionPlugin<Turnout> {
static Name = 'TurnoutPointsDrag';
static init(app: JlDrawApp) {
@ -130,7 +168,7 @@ export class TurnoutPointsInteractionPlugin extends GraphicInteractionPlugin<Tur
TurnoutEditPlugin.Name
);
if (!tep) {
tep = new TurnoutEditPlugin(turnout);
tep = new TurnoutEditPlugin(turnout, { onEditPointCreate });
turnout.addAssistantAppend(tep);
}
tep.reset();
@ -152,14 +190,22 @@ export class TurnoutPointsInteractionPlugin extends GraphicInteractionPlugin<Tur
}
}
type onTurnoutEditPointCreate = (turnout: Turnout, dp: DraggablePoint) => void;
export interface ITurnoutEditOptions {
onEditPointCreate?: onTurnoutEditPointCreate;
}
export class TurnoutEditPlugin extends GraphicEditPlugin<Turnout> {
static Name = 'TurnoutEdit';
options: ITurnoutEditOptions;
editPoints: DraggablePoint[] = [];
labels: VectorText[] = [];
constructor(graphic: Turnout) {
constructor(graphic: Turnout, options?: ITurnoutEditOptions) {
super(graphic);
this.name = TurnoutEditPlugin.Name;
this.options = Object.assign({}, options);
this.initEditPoints();
}
reset(): void {
@ -208,6 +254,9 @@ export class TurnoutEditPlugin extends GraphicEditPlugin<Turnout> {
this.graphic.repaint();
});
if (this.options.onEditPointCreate) {
this.options.onEditPointCreate(this.graphic, dp);
}
this.editPoints.push(dp);
});
this.addChild(...this.editPoints);

View File

@ -55,7 +55,7 @@
import { useQuasar } from 'quasar';
import { ApiError } from 'src/boot/axios';
import { login } from 'src/api/UserApi';
import { saveJwtToken } from 'src/configs/TokenManage';
import { clearJwtToken, saveJwtToken } from 'src/configs/TokenManage';
import { reactive } from 'vue';
import { useRouter } from 'vue-router';
@ -69,6 +69,7 @@ const loginInfo = reactive({
async function doLogin() {
try {
clearJwtToken();
const token = await login(loginInfo);
saveJwtToken(token);
router.push({ name: 'home' });

File diff suppressed because it is too large Load Diff