This commit is contained in:
joylink_zhaoerwei 2024-01-19 16:17:27 +08:00
parent fdf2a9c00e
commit d1f03f2cfc
5 changed files with 37 additions and 916 deletions

View File

@ -22,8 +22,8 @@
"default-passive-events": "^2.0.0",
"echarts": "^5.4.3",
"google-protobuf": "^3.21.2",
"jl-graphic": "git+https://git.code.tencent.com/jl-framework/graphic-pixi.git#v0.1.3",
"rt-graphic-component": "git+https://git.code.tencent.com/jl-framework/rt-graphic-component.git#3c81ca8",
"jl-graphic": "git+https://git.code.tencent.com/jl-framework/graphic-pixi.git#v0.1.8",
"rt-graphic-component": "git+https://git.code.tencent.com/jl-framework/rt-graphic-component.git#5eecd80",
"js-base64": "^3.7.5",
"pinia": "^2.0.11",
"quasar": "^2.6.0",

View File

@ -21,7 +21,11 @@ import { Polygon, PolygonTemplate } from 'src/graphics/polygon/Polygon';
import { PolygonData } from './graphics/PolygonInteraction';
import { PolygonDraw } from 'src/graphics/polygon/PolygonDrawAssistant';
import { StyleType } from 'rt-graphic-component/components/common/common';
import { Platform, PlatformDraw, PlatformTemplate } from 'src/graphics/platform/Platform';
import {
Platform,
PlatformDraw,
PlatformTemplate,
} from 'src/graphics/platform/Platform';
import { PlatformData, PlatformState } from './graphics/PlatformInteraction';
import {
ScreenDoor,
@ -32,7 +36,11 @@ import {
ScreenDoorState,
} from './graphics/ScreenDoorInteraction';
import { ScreenDoorDraw } from 'src/graphics/screenDoor/ScreenDoorDrawAssistant';
import { Station, StationDraw, StationTemplate } from 'src/graphics/station/Station';
import {
Station,
StationDraw,
StationTemplate,
} from 'src/graphics/station/Station';
import { StationData, StationState } from './graphics/StationInteraction';
import {
OneClickGenerateDraw,
@ -50,8 +58,11 @@ import {
} from 'src/graphics/axleCounting/AxleCounting';
import { AxleCountingDraw } from 'src/graphics/axleCounting/AxleCountingDrawAssistant';
import { AxleCountingData } from './graphics/AxleCountingInteraction';
import { Turnout, TurnoutTemplate } from 'src/graphics/turnout/Turnout';
import { TurnoutDraw } from 'src/graphics/turnout/TurnoutDrawAssistant';
import {
Turnout,
TurnoutTemplate,
TurnoutDraw,
} from 'src/graphics/turnout/Turnout';
import { TurnoutData, TurnoutStates } from './graphics/TurnoutInteraction';
import { Section, SectionTemplate } from 'src/graphics/section/Section';
import { SectionDraw } from 'src/graphics/section/SectionDrawAssistant';
@ -176,7 +187,7 @@ export function initCommonDrawApp(app: IDrawApp) {
new SignalDraw(app, new SignalTemplate(new SignalData(), new SignalState()));
new TurnoutDraw(
app,
new TurnoutTemplate(new TurnoutData(), new TurnoutStates())
new TurnoutTemplate(new TurnoutData(), new TurnoutStates(), StyleType.GP)
);
new TrainWindowDraw(app, new TrainWindowTemplate(new TrainWindowData()));
new OneClickGenerateDraw(app, new OneClickGenerateTemplate());

View File

@ -237,7 +237,7 @@ export function initLineScene(lineApp: IGraphicApp, sceneName: string) {
new PlatformTemplate(new PlatformData(), new PlatformState(), StyleType.GP),
new ScreenDoorTemplate(new ScreenDoorData(), new ScreenDoorState()),
new StationTemplate(new StationData(), new StationState(), StyleType.GP),
new TurnoutTemplate(new TurnoutData(), new TurnoutStates()),
new TurnoutTemplate(new TurnoutData(), new TurnoutStates(), StyleType.GP),
new SectionTemplate(new SectionData(), new SectionStates()),
new AxleCountingTemplate(new AxleCountingData()),
new TrainWindowTemplate(new TrainWindowData()),

View File

@ -1,484 +1,18 @@
import { Graphics, IPointData } from 'pixi.js';
import { GPTurnout as Turnout } from 'rt-graphic-component/components/packages/Turnout/GPTurnout';
import { TurnoutSection } from 'rt-graphic-component/components/packages/Turnout/common/JlTurnout';
import {
GraphicAnimation,
GraphicData,
GraphicRelationParam,
GraphicState,
JlGraphic,
JlGraphicTemplate,
VectorText,
angleOfIncludedAngle,
distance2,
} from 'jl-graphic';
import { Section, DevicePort, SectionType } from '../section/Section';
import {
IRelatedRefData,
createRelatedRefProto,
protoPort2Data,
} from '../CommonGraphics';
import { KilometerSystem } from '../signal/Signal';
import { TrackSection } from '../trackSection/TrackSection';
import { graphicData } from 'src/protos/stationLayoutGraphics';
ITurnoutData,
GPConsts as TurnoutConsts,
} from 'rt-graphic-component/components/packages/Turnout/common/TurnoutConfig';
import { TurnoutTemplate } from 'rt-graphic-component/components/packages/Turnout/common/TurnoutTemplate';
import { IGPTurnoutState as ITurnoutState } from 'rt-graphic-component/components/packages/Turnout/GPTurnout';
import { TurnoutDraw } from 'rt-graphic-component/components/packages/Turnout/common/TurnoutDrawAssistant';
const tolerance = 0.01;
export { Turnout, TurnoutTemplate, TurnoutDraw, TurnoutConsts };
export type { ITurnoutState, ITurnoutData, TurnoutSection };
export interface ITurnoutData extends GraphicData {
get code(): string;
set code(code: string);
get pointA(): IPointData[]; //A端点列表(从岔心向外)
set pointA(point: IPointData[]);
get pointB(): IPointData[];
set pointB(point: IPointData[]);
get pointC(): IPointData[];
set pointC(point: IPointData[]);
get paRef(): IRelatedRefData | undefined;
set paRef(ref: IRelatedRefData | undefined);
get pbRef(): IRelatedRefData | undefined;
set pbRef(ref: IRelatedRefData | undefined);
get pcRef(): IRelatedRefData | undefined;
set pcRef(ref: IRelatedRefData | undefined);
get kilometerSystem(): KilometerSystem;
set kilometerSystem(v: KilometerSystem);
get paTrackSectionId(): number;
set paTrackSectionId(v: number);
get pbTrackSectionId(): number;
set pbTrackSectionId(v: number);
get pcTrackSectionId(): number;
set pcTrackSectionId(v: number);
get switchMachineType(): graphicData.Turnout.SwitchMachineType;
set switchMachineType(v: graphicData.Turnout.SwitchMachineType);
get centralizedStations(): number[];
set centralizedStations(v: number[]);
clone(): ITurnoutData;
copyFrom(data: ITurnoutData): void;
eq(other: ITurnoutData): boolean;
}
export interface ITurnoutState extends GraphicState {
id?: number;
normal?: boolean;
reverse?: boolean;
dw?: boolean;
fw?: boolean;
force?: boolean;
sb?: boolean;
dwsb?: boolean;
fwsb?: boolean;
jc?: boolean;
qdc?: boolean;
qfc?: boolean;
qyc?: boolean;
dc?: boolean;
fc?: boolean;
yc?: boolean;
occupied?: boolean;
}
export const TurnoutConsts = {
lineColor: '#5578b6',
occupiedColor: '#f00',
lineWidth: 5,
forkLenth: 20,
labelFontSize: 12,
normalLabelColor: '#0f0',
reverseLabelColor: '#ff0',
};
export enum TurnoutPosition {
NORMAL = 0,
REVERSE = 1,
}
export function getForkPoint(r: number, p: IPointData): IPointData {
if (r === 0) return { x: 0, y: 0 };
const len = Math.sqrt((-p.x) ** 2 + (-p.y) ** 2);
const scale = r / len;
return { x: scale * p.x, y: scale * p.y };
}
export class TurnoutSection extends Graphics {
turnout: Turnout;
port: DevicePort;
constructor(turnout: Turnout, port: DevicePort) {
super();
this.turnout = turnout;
this.port = port;
}
paint() {
let pList: IPointData[] = [];
switch (this.port) {
case DevicePort.A:
pList = this.turnout.datas.pointA;
break;
case DevicePort.B:
pList = this.turnout.datas.pointB;
break;
case DevicePort.C:
pList = this.turnout.datas.pointC;
break;
}
const gap = this.port === DevicePort.A ? 0 : TurnoutConsts.forkLenth;
let color = TurnoutConsts.lineColor;
if (this.turnout.states.occupied) {
if (
this.port === DevicePort.A ||
(this.turnout.states.dw && this.port === DevicePort.B) ||
(this.turnout.states.fw && this.port === DevicePort.C)
) {
color = TurnoutConsts.occupiedColor;
}
}
const start = getForkPoint(gap, pList[0]);
this.clear()
.lineStyle(TurnoutConsts.lineWidth, color)
.moveTo(start.x, start.y);
pList.forEach((p) => {
const { x, y } = p;
this.lineTo(x, y);
});
}
}
class ForkGraphic extends Graphics {
turnout: Turnout;
constructor(turnout: Turnout) {
super();
this.turnout = turnout;
}
paint(p: IPointData) {
const target = getForkPoint(TurnoutConsts.forkLenth, p);
const color = this.turnout.states.occupied
? TurnoutConsts.occupiedColor
: TurnoutConsts.lineColor;
this.clear()
.lineStyle(TurnoutConsts.lineWidth, color)
.moveTo(0, 0)
.lineTo(target.x, target.y);
}
}
export class Turnout extends JlGraphic {
static Type = 'Turnout';
graphics: {
fork: ForkGraphic;
sections: [TurnoutSection, TurnoutSection, TurnoutSection];
label: VectorText;
};
deltaTime: number;
constructor() {
super(Turnout.Type);
this.name = 'turnout';
this.graphics = {
fork: new ForkGraphic(this),
sections: [
new TurnoutSection(this, DevicePort.A),
new TurnoutSection(this, DevicePort.B),
new TurnoutSection(this, DevicePort.C),
],
label: new VectorText(),
};
this.deltaTime = 0;
this.addChild(this.graphics.fork);
// this.addChild(...this.graphics.sections);
this.addChild(this.graphics.sections[0]);
this.addChild(this.graphics.sections[1]);
this.addChild(this.graphics.sections[2]);
this.graphics.label.anchor.set(0.5);
this.graphics.label.style.fill = '#0f0';
this.graphics.label.setVectorFontSize(TurnoutConsts.labelFontSize);
this.graphics.label.position.set(20, 20);
this.graphics.label.transformSave = true;
this.graphics.label.name = 'label';
this.addChild(this.graphics.label);
}
get datas(): ITurnoutData {
return this.getDatas<ITurnoutData>();
}
get states(): ITurnoutState {
return this.getStates<ITurnoutState>();
}
getPortPoints() {
return [this.datas.pointA, this.datas.pointB, this.datas.pointC];
}
doRepaint(): void {
const { pointB, pointC } = this.datas;
if (this.states.dw) {
this.graphics.fork.paint(pointB[0]);
this.graphics.label.style.stroke = TurnoutConsts.normalLabelColor;
} else if (this.states.fw) {
this.graphics.fork.paint(pointC[0]);
this.graphics.label.style.stroke = TurnoutConsts.reverseLabelColor;
}
this.graphics.label.text = this.datas.code;
this.graphics.sections.forEach((sectionGraphic) => sectionGraphic.paint());
if (!this.states.dw && !this.states.fw) {
// 失表
this.graphics.fork.visible = false;
} else {
this.graphics.fork.visible = true;
}
}
initTurnoutSplit() {
// 道岔失表
const name = `${this.datas.id}_turnout_split`;
let turnoutSplit = this.animation(name);
if (!turnoutSplit) {
turnoutSplit = GraphicAnimation.init({
name: name,
run: (dt: number) => {
this.deltaTime += dt;
this.deltaTime = this.deltaTime % 60;
this.graphics.fork.visible = this.deltaTime > 30;
},
});
this.addAnimation(turnoutSplit);
}
turnoutSplit.resume();
}
stopTurnoutSplit() {
const name = `${this.datas.id}_turnout_split`;
const turnoutSplit = this.animation(name);
if (turnoutSplit) {
turnoutSplit.pause();
this.deltaTime = 0;
}
}
getConnectElement(port: DevicePort) {
const relation = this.relationManage
.getRelationsOfGraphic(this)
.find(
(relation) =>
relation.getRelationParam(this).getParam<DevicePort>() === port &&
(relation.getOtherGraphic(this) instanceof Section ||
relation.getOtherGraphic(this) instanceof Turnout)
);
if (!relation) {
return;
}
return {
g: relation?.getOtherGraphic(this) as Section | Turnout,
port: relation?.getOtherRelationParam(this).getParam<DevicePort>(),
};
}
buildRelation(): void {
this.relationManage.deleteRelationOfGraphic(this);
/** 道岔和区段 */
this.queryStore.queryByType<Section>(Section.Type).forEach((section) => {
if (section.datas.sectionType !== SectionType.Physical) return;
this.getPortPoints().forEach((port, i) => {
if (
distance2(
section.localToCanvasPoint(section.getStartPoint()),
this.localToCanvasPoint(port[port.length - 1])
) <= tolerance
) {
this.relationManage.addRelation(
new GraphicRelationParam(
this,
[DevicePort.A, DevicePort.B, DevicePort.C][i]
),
new GraphicRelationParam(section, DevicePort.A)
);
}
if (
distance2(
section.localToCanvasPoint(section.getEndPoint()),
this.localToCanvasPoint(port[port.length - 1])
) <= tolerance
) {
this.relationManage.addRelation(
new GraphicRelationParam(
this,
[DevicePort.A, DevicePort.B, DevicePort.C][i]
),
new GraphicRelationParam(section, DevicePort.B)
);
}
});
});
/** 道岔和道岔 */
this.getPortPoints().forEach((thisPort, i) => {
let params: GraphicRelationParam[] = [],
deflection = 180;
this.queryStore.queryByType<Turnout>(Turnout.Type).forEach((turnout) => {
if (turnout.id === this.id) return;
turnout.getPortPoints().forEach((otherPort, j) => {
if (
distance2(
this.localToCanvasPoint(thisPort[thisPort.length - 1]),
turnout.localToCanvasPoint(otherPort[otherPort.length - 1])
) <= tolerance
) {
const angle = angleOfIncludedAngle(
this.localToCanvasPoint(thisPort[thisPort.length - 1]) /* 交点 */,
thisPort[thisPort.length - 2]
? this.localToCanvasPoint(thisPort[thisPort.length - 2])
: this.position,
otherPort[otherPort.length - 2]
? turnout.localToCanvasPoint(otherPort[otherPort.length - 2])
: turnout.position
);
if (180 - Math.abs(angle) <= deflection) {
deflection = 180 - Math.abs(angle);
params = [
new GraphicRelationParam(
this,
[DevicePort.A, DevicePort.B, DevicePort.C][i]
),
new GraphicRelationParam(
turnout,
[DevicePort.A, DevicePort.B, DevicePort.C][j]
),
];
}
}
});
});
if (params.length === 2) {
this.relationManage.addRelation(params[0], params[1]);
}
});
}
saveRelations() {
const paRelation = this.relationManage
.getRelationsOfGraphic(this)
.find(
(relation) =>
relation.getRelationParam(this).param === DevicePort.A &&
(relation.getOtherGraphic(this) instanceof Section ||
relation.getOtherGraphic(this) instanceof Turnout)
);
const paDevice = paRelation?.getOtherGraphic<Section | Turnout>(this);
if (paDevice) {
this.datas.paRef = createRelatedRefProto(
paDevice.type,
paDevice.id,
paRelation?.getOtherRelationParam(this).param
);
} else {
this.datas.paRef = undefined;
}
const pbRelation = this.relationManage
.getRelationsOfGraphic(this)
.find(
(relation) =>
relation.getRelationParam(this).param === DevicePort.B &&
(relation.getOtherGraphic(this) instanceof Section ||
relation.getOtherGraphic(this) instanceof Turnout)
);
const pbDevice = pbRelation?.getOtherGraphic<Section | Turnout>(this);
if (pbDevice) {
this.datas.pbRef = createRelatedRefProto(
pbDevice.type,
pbDevice.id,
pbRelation?.getOtherRelationParam(this).param
);
} else {
this.datas.pbRef = undefined;
}
const pcRelation = this.relationManage
.getRelationsOfGraphic(this)
.find(
(relation) => relation.getRelationParam(this).param === DevicePort.C
);
const pcDevice = pcRelation?.getOtherGraphic<Section | Turnout>(this);
if (pcDevice) {
this.datas.pcRef = createRelatedRefProto(
pcDevice.type,
pcDevice.id,
pcRelation?.getOtherRelationParam(this).param
);
} else {
this.datas.pcRef = undefined;
}
}
loadRelations() {
if (this.datas.paRef?.id) {
this.relationManage.addRelation(
new GraphicRelationParam(this, DevicePort.A),
new GraphicRelationParam(
this.queryStore.queryById(this.datas.paRef.id),
protoPort2Data(this.datas.paRef.devicePort)
)
);
}
if (this.datas.pbRef?.id) {
this.relationManage.addRelation(
new GraphicRelationParam(this, DevicePort.B),
new GraphicRelationParam(
this.queryStore.queryById(this.datas.pbRef.id),
protoPort2Data(this.datas.pbRef.devicePort)
)
);
}
if (this.datas.pcRef?.id) {
this.relationManage.addRelation(
new GraphicRelationParam(this, DevicePort.C),
new GraphicRelationParam(
this.queryStore.queryById(this.datas.pcRef.id),
protoPort2Data(this.datas.pcRef.devicePort)
)
);
}
if (this.datas.paTrackSectionId) {
this.relationManage.addRelation(
new GraphicRelationParam(this, DevicePort.A),
this.queryStore.queryById<TrackSection>(this.datas.paTrackSectionId)
);
}
if (this.datas.pbTrackSectionId) {
this.relationManage.addRelation(
new GraphicRelationParam(this, DevicePort.B),
this.queryStore.queryById<TrackSection>(this.datas.pbTrackSectionId)
);
}
if (this.datas.paTrackSectionId) {
this.relationManage.addRelation(
new GraphicRelationParam(this, DevicePort.C),
this.queryStore.queryById<TrackSection>(this.datas.pcTrackSectionId)
);
}
}
getGraphicOfPort(port: DevicePort) {
return this.relationManage
.getRelationsOfGraphic(this)
.filter(
(relation) =>
relation.getRelationParam(this).getParam<DevicePort>() === port
)
.map((relation) => {
return relation.getOtherGraphic(this);
});
}
}
export class TurnoutTemplate extends JlGraphicTemplate<Turnout> {
constructor(dataTemplate: ITurnoutData, stateTemplate?: ITurnoutState) {
super(Turnout.Type, {
dataTemplate,
stateTemplate,
});
}
new() {
const g = new Turnout();
g.loadData(this.datas);
g.loadState(this.states);
return g;
}
export enum TurnoutPort {
A = 0,
B = 1,
C = 2,
}

View File

@ -1,430 +1,6 @@
import {
AbsorbablePosition,
DraggablePoint,
IGraphicApp,
GraphicDrawAssistant,
GraphicInteractionPlugin,
GraphicTransformEvent,
IDrawApp,
JlGraphic,
VectorText,
linePoint,
polylinePoint,
AppConsts,
GraphicEditPlugin,
getWaypointRangeIndex,
ContextMenu,
MenuItemOptions,
AbsorbablePoint,
AbsorbableLine,
} from 'jl-graphic';
import {
ITurnoutData,
Turnout,
TurnoutConsts,
TurnoutSection,
TurnoutTemplate,
getForkPoint,
} from './Turnout';
import {
DisplayObject,
FederatedMouseEvent,
IHitArea,
IPointData,
Point,
} from 'pixi.js';
import { DevicePort, Section } from '../section/Section';
ForkHitArea,
TurnoutSectionHitArea,
} from 'rt-graphic-component/components/packages/Turnout/common/TurnoutDrawAssistant';
export class TurnoutDraw extends GraphicDrawAssistant<
TurnoutTemplate,
ITurnoutData
> {
turnout: Turnout;
constructor(app: IDrawApp, template: TurnoutTemplate) {
super(app, template, 'sym_o_ramp_left', '道岔Turnout');
this.turnout = this.graphicTemplate.new();
this.container.addChild(this.turnout);
TurnoutPointsInteractionPlugin.init(app);
}
onLeftUp(e: FederatedMouseEvent): void {
this.turnout.position.copyFrom(this.toCanvasCoordinates(e.global));
this.createAndStore(true);
}
prepareData(data: ITurnoutData): boolean {
data.transform = this.turnout.saveTransform();
data.code = 'A000000';
return true;
}
redraw(cp: Point): void {
this.turnout.position.copyFrom(cp);
}
}
export class ForkHitArea implements IHitArea {
turnout: Turnout;
constructor(turnout: Turnout) {
this.turnout = turnout;
}
contains(x: number, y: number): boolean {
const intersectPointB = getForkPoint(
TurnoutConsts.forkLenth,
this.turnout.datas.pointB[0]
);
const intersectPointC = getForkPoint(
TurnoutConsts.forkLenth,
this.turnout.datas.pointC[0]
);
return (
linePoint(
intersectPointB,
{ x: 0, y: 0 },
{ x, y },
TurnoutConsts.lineWidth
) ||
linePoint(
intersectPointC,
{ x: 0, y: 0 },
{ x, y },
TurnoutConsts.lineWidth
)
);
}
}
export class TurnoutSectionHitArea implements IHitArea {
section: TurnoutSection;
constructor(section: TurnoutSection) {
this.section = section;
}
contains(x: number, y: number): boolean {
let points: IPointData[];
let start: IPointData;
switch (this.section.port) {
case DevicePort.A:
points = this.section.turnout.datas.pointA;
start = { x: 0, y: 0 };
break;
case DevicePort.B:
points = this.section.turnout.datas.pointB;
start = getForkPoint(TurnoutConsts.forkLenth, points[0]);
break;
case DevicePort.C:
points = this.section.turnout.datas.pointC;
start = getForkPoint(TurnoutConsts.forkLenth, points[0]);
break;
}
return polylinePoint([start, ...points], { x, y }, TurnoutConsts.lineWidth);
}
}
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) => {
const {
pointA: [A],
pointB: [B],
pointC: [C],
} = otherTurnout.datas;
[A, B, C].forEach((p) => {
aps.push(
new AbsorbablePoint(otherTurnout.localToCanvasPoint(p)), //道岔端点
new AbsorbableLine(
otherTurnout.localToCanvasPoint({ x: -5 * p.x, y: -5 * p.y }),
otherTurnout.localToCanvasPoint({ x: 5 * p.x, y: 5 * p.y })
) //道岔延长线
);
});
aps.push(
new AbsorbableLine(
otherTurnout.localToCanvasPoint({ x: 0, y: -500 }),
otherTurnout.localToCanvasPoint({ x: 0, y: 500 })
), //岔心垂直线
new AbsorbableLine(
otherTurnout.localToCanvasPoint({ x: -500, y: 0 }),
otherTurnout.localToCanvasPoint({ x: 500, y: 0 })
), //岔心水平线
new AbsorbableLine(
otherTurnout.localToCanvasPoint({ x: -500, y: 500 }),
otherTurnout.localToCanvasPoint({ x: 500, y: -500 })
), //岔心/
new AbsorbableLine(
otherTurnout.localToCanvasPoint({ x: -500, y: -500 }),
otherTurnout.localToCanvasPoint({ x: 500, y: 500 })
) //岔心\
);
});
return aps;
}
function onEditPointCreate(turnout: Turnout, dp: DraggablePoint) {
dp.on('transformstart', (e: GraphicTransformEvent) => {
if (e.isShift()) {
turnout.getGraphicApp().setOptions({
absorbablePositions: buildAbsorbablePositions(turnout),
});
}
});
}
const addPointConfig: MenuItemOptions = { name: '添加路径点' };
const clearPointConfig: MenuItemOptions = { name: '清除路径点' };
const turnoutSectionEditMenu: ContextMenu = ContextMenu.init({
name: '道岔区段路径编辑',
groups: [
{
items: [addPointConfig, clearPointConfig],
},
],
});
export class TurnoutPointsInteractionPlugin extends GraphicInteractionPlugin<Turnout> {
static Name = 'TurnoutPointsDrag';
static init(app: IDrawApp) {
return new TurnoutPointsInteractionPlugin(app);
}
constructor(app: IGraphicApp) {
super(TurnoutPointsInteractionPlugin.Name, app);
app.registerMenu(turnoutSectionEditMenu);
}
onSectionContextMenu(e: FederatedMouseEvent, section: TurnoutSection) {
const p = section.turnout.screenToLocalPoint(e.global);
addPointConfig.handler = () => {
if (section.port === DevicePort.A) {
const { start } = getWaypointRangeIndex(
[{ x: 0, y: 0 }, ...section.turnout.datas.pointA],
false,
p,
TurnoutConsts.lineWidth
);
const points = section.turnout.datas.pointA;
const ps = points.slice(0, start);
ps.push(new Point(p.x, p.y));
ps.push(...points.slice(start));
section.turnout.datas.pointA = ps;
}
if (section.port === DevicePort.B) {
const { start } = getWaypointRangeIndex(
[{ x: 0, y: 0 }, ...section.turnout.datas.pointB],
false,
p,
TurnoutConsts.lineWidth
);
const points = section.turnout.datas.pointB;
const ps = points.slice(0, start);
ps.push(new Point(p.x, p.y));
ps.push(...points.slice(start));
section.turnout.datas.pointB = ps;
}
if (section.port === DevicePort.C) {
const { start } = getWaypointRangeIndex(
[{ x: 0, y: 0 }, ...section.turnout.datas.pointC],
false,
p,
TurnoutConsts.lineWidth
);
const points = section.turnout.datas.pointC;
const ps = points.slice(0, start);
ps.push(new Point(p.x, p.y));
ps.push(...points.slice(start));
section.turnout.datas.pointC = ps;
}
this.onSelected(section.turnout);
};
clearPointConfig.handler = () => {
if (section.port === DevicePort.A)
section.turnout.datas.pointA = [
section.turnout.datas.pointA[section.turnout.datas.pointA.length - 1],
];
if (section.port === DevicePort.B)
section.turnout.datas.pointB = [
section.turnout.datas.pointB[section.turnout.datas.pointB.length - 1],
];
if (section.port === DevicePort.C)
section.turnout.datas.pointC = [
section.turnout.datas.pointC[section.turnout.datas.pointC.length - 1],
];
const tep = section.turnout.getAssistantAppend<TurnoutEditPlugin>(
TurnoutEditPlugin.Name
);
if (tep) {
tep.reset();
}
section.turnout.repaint();
};
turnoutSectionEditMenu.open(e.global);
}
bind(g: Turnout): void {
g.graphics.fork.eventMode = 'static';
g.graphics.fork.cursor = 'pointer';
g.graphics.fork.hitArea = new ForkHitArea(g);
g.graphics.sections.forEach((sectionGraphic) => {
sectionGraphic.eventMode = 'static';
sectionGraphic.cursor = 'pointer';
sectionGraphic.hitArea = new TurnoutSectionHitArea(sectionGraphic);
sectionGraphic.on(
'rightclick',
(e) => this.onSectionContextMenu(e, sectionGraphic),
sectionGraphic
);
});
g.graphics.label.eventMode = 'static';
g.graphics.label.cursor = 'pointer';
g.graphics.label.draggable = true;
g.graphics.label.selectable = true;
g.graphics.label.name = 'label';
g.graphics.label.transformSave = true;
g.transformSave = true;
g.on('selected', this.onSelected, this);
g.on('unselected', this.onUnSelected, this);
}
unbind(g: Turnout): void {
g.off('selected', this.onSelected, this);
g.off('unselected', this.onUnSelected, this);
g.graphics.sections.forEach((sectionGraphic) => {
sectionGraphic.off('rightclick');
});
}
onSelected(g: DisplayObject) {
const turnout = g as Turnout;
let tep = turnout.getAssistantAppend<TurnoutEditPlugin>(
TurnoutEditPlugin.Name
);
if (!tep) {
tep = new TurnoutEditPlugin(turnout, { onEditPointCreate });
turnout.addAssistantAppend(tep);
}
tep.reset();
tep.showAll();
}
onUnSelected(g: DisplayObject) {
const turnout = g as Turnout;
const tep = turnout.getAssistantAppend<TurnoutEditPlugin>(
TurnoutEditPlugin.Name
);
if (tep) {
tep.hideAll();
}
}
filter(...grahpics: JlGraphic[]): Turnout[] | undefined {
return grahpics.filter((g) => g.type == Turnout.Type) as Turnout[];
}
}
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, options?: ITurnoutEditOptions) {
super(graphic);
this.name = TurnoutEditPlugin.Name;
this.options = Object.assign({}, options);
this.initEditPoints();
}
reset(): void {
this.destoryEditPoints();
this.removeChildren();
this.initEditPoints();
}
hideAll(): void {
super.hideAll();
}
initEditPoints() {
const cpA = this.graphic.localToCanvasPoints(...this.graphic.datas.pointA);
const cpB = this.graphic.localToCanvasPoints(...this.graphic.datas.pointB);
const cpC = this.graphic.localToCanvasPoints(...this.graphic.datas.pointC);
const cpMap: Map<Point[], IPointData[]> = new Map([
[cpA, this.graphic.datas.pointA],
[cpB, this.graphic.datas.pointB],
[cpC, this.graphic.datas.pointC],
]);
Array.from(cpMap.entries()).forEach(([cpDatas, dataPoints], i) => {
cpDatas.forEach((cpData, j) => {
const dp = new DraggablePoint(cpData);
dp.on('transforming', () => {
const localPoint = this.graphic.canvasToLocalPoint(dp.position);
dataPoints[j].x = localPoint.x;
dataPoints[j].y = localPoint.y;
this.graphic.repaint();
});
if (this.options.onEditPointCreate) {
this.options.onEditPointCreate(this.graphic, dp);
}
this.editPoints[i].push(dp);
});
});
this.editPoints.forEach((cps) => {
this.addChild(...cps);
});
this.labels = ['A', 'B', 'C'].map((str) => {
const vc = new VectorText(str, { fill: AppConsts.assistantElementColor });
vc.setVectorFontSize(14);
vc.anchor.set(0.5);
return vc;
});
this.addChild(...this.labels);
}
destoryEditPoints() {
this.editPoints.forEach((dps) => {
dps.forEach((dp) => {
dp.off('transforming');
dp.destroy();
this.removeChild(dp);
});
});
this.editPoints = [[], [], []];
}
updateEditedPointsPosition() {
const cpA = this.graphic.localToCanvasPoints(...this.graphic.datas.pointA);
const cpB = this.graphic.localToCanvasPoints(...this.graphic.datas.pointB);
const cpC = this.graphic.localToCanvasPoints(...this.graphic.datas.pointC);
[cpA, cpB, cpC].forEach((cps, i) => {
cps.forEach((cp, j) => {
this.editPoints[i][j].position.copyFrom(cp);
if (j === cps.length - 1) {
this.labels[i].position.copyFrom({ x: cp.x, y: cp.y + 12 });
}
});
});
}
}
export { ForkHitArea, TurnoutSectionHitArea };