|
|
|
import { WorkingAreaComponent } from '../working-area.component';
|
|
|
|
import * as PIXI from 'pixi.js';
|
|
|
|
import { AxShape } from './axShape';
|
|
|
|
import { Sprite } from 'pixi.js';
|
|
|
|
import { GameMode } from './gameMode';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 连接箭头
|
|
|
|
*/
|
|
|
|
export class AxArrowConnector extends AxShape {
|
|
|
|
pointSprites: Array<Sprite> = new Array<Sprite>();
|
|
|
|
tempLine: PIXI.Graphics;
|
|
|
|
text: PIXI.Text;
|
|
|
|
style = new PIXI.TextStyle({
|
|
|
|
fontFamily: 'Arial',
|
|
|
|
fontSize: 18,
|
|
|
|
fontStyle: 'normal',
|
|
|
|
fontWeight: 'bold',
|
|
|
|
fill: ['#000000'],
|
|
|
|
stroke: '#ffffff',
|
|
|
|
strokeThickness: 3,
|
|
|
|
dropShadow: true,
|
|
|
|
dropShadowColor: '#000000',
|
|
|
|
dropShadowBlur: 3,
|
|
|
|
dropShadowAngle: Math.PI / 6,
|
|
|
|
dropShadowDistance: 1,
|
|
|
|
wordWrap: false,
|
|
|
|
wordWrapWidth: 100,
|
|
|
|
});
|
|
|
|
pts: PIXI.Point[];
|
|
|
|
|
|
|
|
markerStart = true; // 是否绘制起始箭头
|
|
|
|
markerEnd = true; // 是否绘制结束箭头
|
|
|
|
constructor(assetData: any, workingArea: WorkingAreaComponent, markerStart: boolean, markerEnd: boolean) {
|
|
|
|
super(assetData, workingArea);
|
|
|
|
|
|
|
|
this.markerStart = markerStart;
|
|
|
|
this.markerEnd = markerEnd;
|
|
|
|
|
|
|
|
this.name = assetData.Id;
|
|
|
|
this.text = new PIXI.Text(this.assetData.Name
|
|
|
|
+ '\r\n'
|
|
|
|
+ this.assetData.PropertyInfos?.find((item: { PropertyName: string; }) =>
|
|
|
|
item.PropertyName === '名称/编号')?.PropertyValue, this.style);
|
|
|
|
this.tempLine = new PIXI.Graphics();
|
|
|
|
this.addChild(this.text);
|
|
|
|
this.addChild(this.tempLine);
|
|
|
|
this.workingArea.backgroundImage.addChild(this);
|
|
|
|
this.refresh();
|
|
|
|
this.drawPoints();
|
|
|
|
this.sortableChildren = true;
|
|
|
|
this.text.zIndex = this.children.length;
|
|
|
|
this.text.visible = this.showName;
|
|
|
|
this.text.angle = -this.workingArea.backgroundImage.angle;
|
|
|
|
}
|
|
|
|
|
|
|
|
public drawPoints() {
|
|
|
|
this.assetData.MultiPoint.forEach(element => {
|
|
|
|
const point = new Sprite(this.pointTexture);
|
|
|
|
point.position = element;
|
|
|
|
point.anchor.set(0.5);
|
|
|
|
this.pointSprites.push(point);
|
|
|
|
this.addChild(point);
|
|
|
|
});
|
|
|
|
this.pointSprites.forEach((value, index, array) => {
|
|
|
|
value.interactive = true;
|
|
|
|
value
|
|
|
|
.on('pointerdown', event => {
|
|
|
|
event.stopPropagation();
|
|
|
|
if (this.workingArea.allowEdit && this.assetData.GameMode === this.workingArea.canvasData.gameMode) {
|
|
|
|
event.currentTarget.data = event.data;
|
|
|
|
event.currentTarget.alpha = 0.5;
|
|
|
|
event.currentTarget.dragging = true;
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.on('pointerup', event => {
|
|
|
|
if (event.currentTarget.dragging) {
|
|
|
|
event.currentTarget.alpha = 1;
|
|
|
|
event.currentTarget.dragging = false;
|
|
|
|
event.currentTarget.data = null;
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.on('pointerupoutside', event => {
|
|
|
|
if (event.currentTarget.dragging) {
|
|
|
|
event.currentTarget.alpha = 1;
|
|
|
|
event.currentTarget.dragging = false;
|
|
|
|
event.currentTarget.data = null;
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.on('pointermove', event => {
|
|
|
|
if (event.currentTarget.dragging) {
|
|
|
|
const newPosition = event.currentTarget.data.getLocalPosition(event.currentTarget.parent);
|
|
|
|
event.currentTarget.x = newPosition.x;
|
|
|
|
event.currentTarget.y = newPosition.y;
|
|
|
|
|
|
|
|
this.assetData.MultiPoint[index].x = newPosition.x;
|
|
|
|
this.assetData.MultiPoint[index].y = newPosition.y;
|
|
|
|
this.workingArea.canvasData.isChange = true;
|
|
|
|
this.refresh();
|
|
|
|
this.drawBorder(1 / this.workingArea.backgroundImage.scale.x);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.on('rightclick', event => {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
this.setPointVisiable(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 设置点显示状态
|
|
|
|
* @param b true/false
|
|
|
|
*/
|
|
|
|
public setPointVisiable(b: boolean) {
|
|
|
|
this.pointSprites.forEach(item => {
|
|
|
|
item.visible = b;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
// 设置缩放
|
|
|
|
public setItemScale(scale: number) {
|
|
|
|
// this.text.scale.set(scale);
|
|
|
|
this.pointSprites.forEach(point => {
|
|
|
|
point.scale.set(scale);
|
|
|
|
});
|
|
|
|
this.refresh();
|
|
|
|
}
|
|
|
|
public setNameVisible(value: boolean, mode: GameMode) {
|
|
|
|
if (this.assetData.GameMode === mode) {
|
|
|
|
this.text.visible = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param scale 绘制边框
|
|
|
|
*/
|
|
|
|
public drawBorder(scale: number) {
|
|
|
|
const visible = this.pointSprites[0].visible;
|
|
|
|
this.setPointVisiable(false);
|
|
|
|
super.drawBorder(scale);
|
|
|
|
this.setPointVisiable(visible);
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* 刷新形状
|
|
|
|
*/
|
|
|
|
public refresh(): void {
|
|
|
|
const c = this.tempLine;
|
|
|
|
const pts = this.assetData.MultiPoint;
|
|
|
|
if (pts.length < 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.text.position = this.getLineCenter(pts[0], pts[1]);
|
|
|
|
this.text.anchor.set(0.5);
|
|
|
|
this.text.text = this.assetData.Name
|
|
|
|
+ '\r\n'
|
|
|
|
+ this.assetData.PropertyInfos?.find(item => item.PropertyName === '名称/编号')?.PropertyValue;
|
|
|
|
const strokeWidth = 1;
|
|
|
|
|
|
|
|
const edgeWidth = this.assetData.Thickness === 0 ? 1 : this.assetData.Thickness; // 宽度
|
|
|
|
|
|
|
|
const startWidth = edgeWidth * 2 + strokeWidth;
|
|
|
|
const endWidth = edgeWidth * 2 + strokeWidth;
|
|
|
|
|
|
|
|
const openEnded = false;
|
|
|
|
|
|
|
|
const spacing = (openEnded) ? 0 : 0 + strokeWidth / 2;
|
|
|
|
|
|
|
|
const startSize = edgeWidth * 2 + strokeWidth;
|
|
|
|
const endSize = edgeWidth * 2 + strokeWidth;
|
|
|
|
|
|
|
|
const isRounded = true;
|
|
|
|
const lineColor = 0x000000;
|
|
|
|
const fillColor: number = this.assetData.Color.substring(0, 7).replace('#', '0x');
|
|
|
|
|
|
|
|
const pe = pts[pts.length - 1];
|
|
|
|
|
|
|
|
let i0 = 1;
|
|
|
|
|
|
|
|
while (i0 < pts.length - 1 && pts[i0].x === pts[0].x && pts[i0].y === pts[0].y) {
|
|
|
|
i0++;
|
|
|
|
}
|
|
|
|
|
|
|
|
const dx = pts[i0].x - pts[0].x;
|
|
|
|
const dy = pts[i0].y - pts[0].y;
|
|
|
|
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
|
|
|
|
|
|
if (dist === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let nx = dx / dist;
|
|
|
|
let nx1 = nx;
|
|
|
|
let nx2 = nx;
|
|
|
|
let ny = dy / dist;
|
|
|
|
let ny2 = ny;
|
|
|
|
let ny1 = ny;
|
|
|
|
let orthx = edgeWidth * ny;
|
|
|
|
let orthy = -edgeWidth * nx;
|
|
|
|
|
|
|
|
const fns = [];
|
|
|
|
|
|
|
|
// if (isRounded) {
|
|
|
|
// // c.setLineJoin('round');
|
|
|
|
// c.lineTextureStyle({ join: PIXI.LINE_JOIN.ROUND });
|
|
|
|
// } else if (pts.length > 2) {
|
|
|
|
// // Only mitre if there are waypoints
|
|
|
|
// // c.setMiterLimit(1.42);
|
|
|
|
// c.lineTextureStyle({ miterLimit: 1.42 });
|
|
|
|
// }
|
|
|
|
// c.lineStyle(1, 0x000000, 1);
|
|
|
|
c.clear();
|
|
|
|
c.lineTextureStyle({ width: 1 / this.workingArea.backgroundImage.scale.x, color: lineColor, join: PIXI.LINE_JOIN.ROUND });
|
|
|
|
|
|
|
|
const startNx = nx;
|
|
|
|
const startNy = ny;
|
|
|
|
if (!openEnded) {
|
|
|
|
c.beginFill(fillColor);
|
|
|
|
}
|
|
|
|
if (this.markerStart && !openEnded) {
|
|
|
|
this.paintMarker(c, pts[0].x, pts[0].y, nx, ny, startSize, startWidth, edgeWidth, spacing, true);
|
|
|
|
} else {
|
|
|
|
const outStartX = pts[0].x + orthx / 2 + spacing * nx;
|
|
|
|
const outStartY = pts[0].y + orthy / 2 + spacing * ny;
|
|
|
|
const inEndX = pts[0].x - orthx / 2 + spacing * nx;
|
|
|
|
const inEndY = pts[0].y - orthy / 2 + spacing * ny;
|
|
|
|
|
|
|
|
if (openEnded) {
|
|
|
|
c.moveTo(outStartX, outStartY);
|
|
|
|
fns.push( () => {
|
|
|
|
c.lineTo(inEndX, inEndY);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
c.moveTo(inEndX, inEndY);
|
|
|
|
c.lineTo(outStartX, outStartY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let dx1 = 0;
|
|
|
|
let dy1 = 0;
|
|
|
|
let dist1 = 0;
|
|
|
|
|
|
|
|
for (let i = 0; i < pts.length - 2; i++) {
|
|
|
|
const pos = this.relativeCcw(pts[i].x, pts[i].y, pts[i + 1].x, pts[i + 1].y, pts[i + 2].x, pts[i + 2].y);
|
|
|
|
|
|
|
|
dx1 = pts[i + 2].x - pts[i + 1].x;
|
|
|
|
dy1 = pts[i + 2].y - pts[i + 1].y;
|
|
|
|
|
|
|
|
dist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
|
|
|
|
|
|
|
|
if (dist1 !== 0) {
|
|
|
|
nx1 = dx1 / dist1;
|
|
|
|
ny1 = dy1 / dist1;
|
|
|
|
|
|
|
|
const tmp1 = nx * nx1 + ny * ny1;
|
|
|
|
const tmp = Math.max(Math.sqrt((tmp1 + 1) / 2), 0.04);
|
|
|
|
|
|
|
|
nx2 = (nx + nx1);
|
|
|
|
ny2 = (ny + ny1);
|
|
|
|
|
|
|
|
const dist2 = Math.sqrt(nx2 * nx2 + ny2 * ny2);
|
|
|
|
|
|
|
|
if (dist2 !== 0) {
|
|
|
|
nx2 = nx2 / dist2;
|
|
|
|
ny2 = ny2 / dist2;
|
|
|
|
|
|
|
|
const strokeWidthFactor = Math.max(tmp, Math.min(1 / 200 + 0.04, 0.35));
|
|
|
|
const angleFactor = (pos !== 0 && isRounded) ? Math.max(0.1, strokeWidthFactor) : Math.max(tmp, 0.06);
|
|
|
|
|
|
|
|
const outX = pts[i + 1].x + ny2 * edgeWidth / 2 / angleFactor;
|
|
|
|
const outY = pts[i + 1].y - nx2 * edgeWidth / 2 / angleFactor;
|
|
|
|
const inX = pts[i + 1].x - ny2 * edgeWidth / 2 / angleFactor;
|
|
|
|
const inY = pts[i + 1].y + nx2 * edgeWidth / 2 / angleFactor;
|
|
|
|
|
|
|
|
if (pos === 0 || !isRounded) {
|
|
|
|
c.lineTo(outX, outY);
|
|
|
|
|
|
|
|
((x, y) => {
|
|
|
|
fns.push(() => {
|
|
|
|
c.lineTo(x, y);
|
|
|
|
});
|
|
|
|
})(inX, inY);
|
|
|
|
} else if (pos === -1) {
|
|
|
|
const c1x = inX + ny * edgeWidth;
|
|
|
|
const c1y = inY - nx * edgeWidth;
|
|
|
|
const c2x = inX + ny1 * edgeWidth;
|
|
|
|
const c2y = inY - nx1 * edgeWidth;
|
|
|
|
c.lineTo(c1x, c1y);
|
|
|
|
if (isRounded) {
|
|
|
|
c.quadraticCurveTo(outX, outY, c2x, c2y); // 圆角
|
|
|
|
} else {
|
|
|
|
c.lineTo(outX, outY);
|
|
|
|
}
|
|
|
|
((x, y) => {
|
|
|
|
fns.push(() => {
|
|
|
|
c.lineTo(x, y);
|
|
|
|
});
|
|
|
|
})(inX, inY);
|
|
|
|
} else {
|
|
|
|
c.lineTo(outX, outY);
|
|
|
|
|
|
|
|
((x, y) => {
|
|
|
|
const c1x = outX - ny * edgeWidth;
|
|
|
|
const c1y = outY + nx * edgeWidth;
|
|
|
|
const c2x = outX - ny1 * edgeWidth;
|
|
|
|
const c2y = outY + nx1 * edgeWidth;
|
|
|
|
|
|
|
|
fns.push(() => {
|
|
|
|
if (isRounded) {
|
|
|
|
c.quadraticCurveTo(x, y, c1x, c1y);
|
|
|
|
} else {
|
|
|
|
c.lineTo(x, y);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
fns.push(() => {
|
|
|
|
c.lineTo(c2x, c2y);
|
|
|
|
});
|
|
|
|
})(inX, inY);
|
|
|
|
}
|
|
|
|
|
|
|
|
nx = nx1;
|
|
|
|
ny = ny1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
orthx = edgeWidth * ny1;
|
|
|
|
orthy = - edgeWidth * nx1;
|
|
|
|
|
|
|
|
if (this.markerEnd && !openEnded) {
|
|
|
|
this.paintMarker(c, pe.x, pe.y, -nx, -ny, endSize, endWidth, edgeWidth, spacing, false);
|
|
|
|
} else {
|
|
|
|
c.lineTo(pe.x - spacing * nx1 + orthx / 2, pe.y - spacing * ny1 + orthy / 2);
|
|
|
|
|
|
|
|
const inStartX = pe.x - spacing * nx1 - orthx / 2;
|
|
|
|
const inStartY = pe.y - spacing * ny1 - orthy / 2;
|
|
|
|
|
|
|
|
if (!openEnded) {
|
|
|
|
c.lineTo(inStartX, inStartY);
|
|
|
|
} else {
|
|
|
|
c.moveTo(inStartX, inStartY);
|
|
|
|
|
|
|
|
fns.splice(0, 0, () => {
|
|
|
|
c.moveTo(inStartX, inStartY);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = fns.length - 1; i >= 0; i--) {
|
|
|
|
fns[i]();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (openEnded) {
|
|
|
|
c.closePath();
|
|
|
|
} else {
|
|
|
|
c.closePath();
|
|
|
|
c.endFill();
|
|
|
|
}
|
|
|
|
|
|
|
|
// c.setShadow(false);
|
|
|
|
|
|
|
|
// c.setMiterLimit(4);
|
|
|
|
|
|
|
|
// if (isRounded)
|
|
|
|
// {
|
|
|
|
// c.setLineJoin('flat');
|
|
|
|
// }
|
|
|
|
|
|
|
|
// if (pts.length > 2)
|
|
|
|
// {
|
|
|
|
// c.setMiterLimit(4);
|
|
|
|
// if (markerStart && !openEnded)
|
|
|
|
// {
|
|
|
|
// c.begin();
|
|
|
|
// this.paintMarker(c, pts[0].x, pts[0].y, startNx, startNy, startSize, startWidth, edgeWidth, spacing, true);
|
|
|
|
// c.stroke();
|
|
|
|
// c.end();
|
|
|
|
// }
|
|
|
|
|
|
|
|
// if (markerEnd && !openEnded)
|
|
|
|
// {
|
|
|
|
// c.begin();
|
|
|
|
// this.paintMarker(c, pe.x, pe.y, -nx, -ny, endSize, endWidth, edgeWidth, spacing, true);
|
|
|
|
// c.stroke();
|
|
|
|
// c.end();
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
this.text.angle = -this.workingArea.backgroundImage.angle;
|
|
|
|
}
|
|
|
|
paintMarker(c: PIXI.Graphics, ptX: number, ptY: number, nx: number, ny: number,
|
|
|
|
size: number, arrowWidth: number, edgeWidth: number, spacing: number, initialMove: boolean) {
|
|
|
|
const widthArrowRatio = edgeWidth / arrowWidth;
|
|
|
|
const orthx = edgeWidth * ny / 2;
|
|
|
|
const orthy = -edgeWidth * nx / 2;
|
|
|
|
|
|
|
|
const spaceX = (spacing + size) * nx;
|
|
|
|
const spaceY = (spacing + size) * ny;
|
|
|
|
|
|
|
|
if (initialMove) {
|
|
|
|
c.moveTo(ptX - orthx + spaceX, ptY - orthy + spaceY);
|
|
|
|
} else {
|
|
|
|
c.lineTo(ptX - orthx + spaceX, ptY - orthy + spaceY);
|
|
|
|
}
|
|
|
|
c.lineTo(ptX - orthx / widthArrowRatio + spaceX, ptY - orthy / widthArrowRatio + spaceY);
|
|
|
|
c.lineTo(ptX + spacing * nx, ptY + spacing * ny);
|
|
|
|
c.lineTo(ptX + orthx / widthArrowRatio + spaceX, ptY + orthy / widthArrowRatio + spaceY);
|
|
|
|
c.lineTo(ptX + orthx + spaceX, ptY + orthy + spaceY);
|
|
|
|
}
|
|
|
|
relativeCcw(x1: number, y1: number, x2: number, y2: number, px: number, py: number) {
|
|
|
|
x2 -= x1;
|
|
|
|
y2 -= y1;
|
|
|
|
px -= x1;
|
|
|
|
py -= y1;
|
|
|
|
let ccw = px * y2 - py * x2;
|
|
|
|
|
|
|
|
if (ccw === 0.0) {
|
|
|
|
ccw = px * x2 + py * y2;
|
|
|
|
|
|
|
|
if (ccw > 0.0) {
|
|
|
|
px -= x2;
|
|
|
|
py -= y2;
|
|
|
|
ccw = px * x2 + py * y2;
|
|
|
|
|
|
|
|
if (ccw < 0.0) {
|
|
|
|
ccw = 0.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (ccw < 0.0) ? -1 : ((ccw > 0.0) ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
redraw(): void {
|
|
|
|
this.pointSprites.forEach(item => {
|
|
|
|
item.destroy();
|
|
|
|
});
|
|
|
|
this.pointSprites.splice(0, this.pointSprites.length);
|
|
|
|
this.refresh();
|
|
|
|
this.drawPoints();
|
|
|
|
}
|
|
|
|
}
|