From 26e554367e057d054bf11d870f7c707b80076161 Mon Sep 17 00:00:00 2001
From: Junjie <DELL@qq.com>
Date: 星期二, 03 二月 2026 16:30:31 +0800
Subject: [PATCH] #
---
src/main/webapp/components/MapCanvas.js | 266 +++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 237 insertions(+), 29 deletions(-)
diff --git a/src/main/webapp/components/MapCanvas.js b/src/main/webapp/components/MapCanvas.js
index be746ba..598a962 100644
--- a/src/main/webapp/components/MapCanvas.js
+++ b/src/main/webapp/components/MapCanvas.js
@@ -37,6 +37,7 @@
objectsContainer: null,
objectsContainer2: null,
tracksContainer: null,
+ tracksGraphics: null,
shelvesContainer: null,
graphicsCrn: null,
graphicsCrnTrack: null,
@@ -127,14 +128,16 @@
this.pixiApp.view.style.display = 'block';
this.resizeToContainer();
window.addEventListener('resize', this.resizeToContainer);
- this.graphicsCrnTrack = this.createTrackTexture(25,25);
- this.graphicsRgvTrack = this.createTrackTexture(25,25);
+ this.graphicsCrnTrack = this.createTrackTexture(25, 25, 10);
+ this.graphicsRgvTrack = this.createTrackTexture(25, 25, 10);
this.objectsContainer = new PIXI.Container();
this.objectsContainer2 = new PIXI.Container();
this.tracksContainer = new PIXI.ParticleContainer(10000, { scale: true, position: true, rotation: false, uvs: false, alpha: false });
+ this.tracksGraphics = new PIXI.Graphics();
this.shelvesContainer = new PIXI.ParticleContainer(10000, { scale: true, position: true, rotation: false, uvs: false, alpha: false });
this.tracksContainer.autoResize = true;
this.shelvesContainer.autoResize = true;
+ this.pixiApp.stage.addChild(this.tracksGraphics);
this.pixiApp.stage.addChild(this.tracksContainer);
this.pixiApp.stage.addChild(this.shelvesContainer);
this.pixiApp.stage.addChild(this.objectsContainer);
@@ -222,6 +225,7 @@
this.objectsContainer.removeChildren();
this.objectsContainer2.removeChildren();
if (this.tracksContainer) { this.tracksContainer.removeChildren(); }
+ if (this.tracksGraphics) { this.tracksGraphics.clear(); }
if (this.shelvesContainer) { this.shelvesContainer.removeChildren(); }
this.crnList = [];
this.dualCrnList = [];
@@ -243,6 +247,7 @@
this.objectsContainer.removeChildren();
this.objectsContainer2.removeChildren();
if (this.tracksContainer) { this.tracksContainer.removeChildren(); }
+ if (this.tracksGraphics) { this.tracksGraphics.clear(); }
if (this.shelvesContainer) { this.shelvesContainer.removeChildren(); }
this.crnList = [];
this.dualCrnList = [];
@@ -342,20 +347,24 @@
}
});
+ this.drawTracks(map);
+
map.forEach((item, index) => {
this.pixiStageList[index] = [item.length];
for (let idx = 0; idx < item.length; idx++) {
let val = item[idx];
if (val.type === 'merge') { continue; }
if (val.type == undefined || val.type === 'none') { continue; }
+ if (this.isTrackType(val)) {
+ this.collectTrackItem(val);
+ continue;
+ }
let sprite = this.getSprite(val, (e) => {
//鍥炶皟
});
if (sprite == null) { continue; }
if (sprite._kind === 'shelf') {
this.shelvesContainer.addChild(sprite);
- } else if (sprite._kind === 'crn-track' || sprite._kind === 'rgv-track') {
- this.tracksContainer.addChild(sprite);
} else {
this.objectsContainer.addChild(sprite);
}
@@ -779,11 +788,12 @@
}
return new PIXI.Sprite(texture);
},
- createTrackSprite(width, height) {
- let idx = width + "-" + height;
+ createTrackSprite(width, height, mask) {
+ const trackMask = mask != null ? mask : 10;
+ let idx = width + "-" + height + "-" + trackMask;
let texture = this.pixiTrackMap.get(idx);
if (texture == undefined) {
- texture = this.createTrackTexture(width, height);
+ texture = this.createTrackTexture(width, height, trackMask);
this.pixiTrackMap.set(idx, texture);
}
return new PIXI.Sprite(texture);
@@ -798,26 +808,71 @@
graphics.endFill();
return graphics;
},
- createTrackTexture(width, height) {
+ createTrackTexture(width, height, mask) {
+ const TRACK_N = 1;
+ const TRACK_E = 2;
+ const TRACK_S = 4;
+ const TRACK_W = 8;
+ const trackMask = mask != null ? mask : (TRACK_E | TRACK_W);
const g = new PIXI.Graphics();
- const t = Math.max(2, Math.round(height * 0.08));
- const gap = Math.round(height * 0.30);
- const mid = Math.round(height / 2);
- const y1 = mid - Math.round(gap / 2);
- const y2 = mid + Math.round(gap / 2);
- const tHalf = Math.round(t / 2);
- const topRailTopY = y1 - tHalf;
- const bottomRailTopY = y2 - tHalf;
- g.beginFill(0x666666);
- g.drawRect(0, topRailTopY, width, t);
- g.drawRect(0, bottomRailTopY, width, t);
- g.endFill();
- g.beginFill(0x777777);
- const sTop = topRailTopY + t;
- const sBottom = bottomRailTopY;
- const sHeight = Math.max(1, sBottom - sTop);
- for (let i = 0; i < width; i += 5) { g.drawRect(i, sTop, 2, sHeight); }
- g.endFill();
+ const size = Math.max(1, Math.min(width, height));
+ const rail = Math.max(2, Math.round(size * 0.12));
+ const gap = Math.max(4, Math.round(size * 0.38));
+ const midX = Math.round(width / 2);
+ const midY = Math.round(height / 2);
+ const y1 = midY - Math.round(gap / 2);
+ const y2 = midY + Math.round(gap / 2);
+ const x1 = midX - Math.round(gap / 2);
+ const x2 = midX + Math.round(gap / 2);
+
+ const hasN = (trackMask & TRACK_N) !== 0;
+ const hasE = (trackMask & TRACK_E) !== 0;
+ const hasS = (trackMask & TRACK_S) !== 0;
+ const hasW = (trackMask & TRACK_W) !== 0;
+
+ const hStart = hasW ? 0 : midX;
+ const hEnd = hasE ? width : midX;
+ const vStart = hasN ? 0 : midY;
+ const vEnd = hasS ? height : midY;
+
+ const railColor = 0x555555;
+ const drawLine = (x1p, y1p, x2p, y2p, w, color) => {
+ g.lineStyle(w, color, 1);
+ g.moveTo(x1p, y1p);
+ g.lineTo(x2p, y2p);
+ };
+
+ const hasH = hasW || hasE;
+ const hasV = hasN || hasS;
+ const isCorner = hasH && hasV && !(hasW && hasE) && !(hasN && hasS);
+ if (hasH && !isCorner) {
+ const w = Math.max(1, hEnd - hStart);
+ g.beginFill(railColor);
+ g.drawRect(hStart, midY - Math.round(rail / 2), w, rail);
+ g.endFill();
+ }
+ if (hasV && !isCorner) {
+ const h = Math.max(1, vEnd - vStart);
+ g.beginFill(railColor);
+ g.drawRect(midX - Math.round(rail / 2), vStart, rail, h);
+ g.endFill();
+ }
+ if (isCorner) {
+ const cw = hasE;
+ const ch = hasS;
+ const cx = cw ? (width - 1) : 0;
+ const cy = ch ? (height - 1) : 0;
+ const angStart = (cw && ch) ? Math.PI : (cw ? Math.PI / 2 : (ch ? -Math.PI / 2 : 0));
+ const angEnd = (cw && ch) ? Math.PI * 1.5 : (cw ? Math.PI : (ch ? 0 : Math.PI / 2));
+ const rX = Math.abs(cx - midX);
+ const rY = Math.abs(cy - midY);
+ const rMid = Math.min(rX, rY);
+ g.lineStyle(rail, railColor, 1);
+ g.arc(cx, cy, rMid, angStart, angEnd);
+ g.lineStyle(0, 0, 0);
+ }
+
+ // no sleepers; keep a single continuous line
const rt = PIXI.RenderTexture.create({ width: width, height: height });
this.pixiApp.renderer.render(g, rt);
return rt;
@@ -1049,15 +1104,15 @@
if (!isNaN(id)) { this.$emit('station-click', id); }
});
} else if (item.type == 'crn') {
- sprite = this.createTrackSprite(item.width, item.height);
+ sprite = this.createTrackSprite(item.width, item.height, item.trackMask);
sprite._kind = 'crn-track';
if (this.getDeviceNo(value) > 0) { this.crnList.push(item); }
} else if (item.type == 'dualCrn') {
- sprite = this.createTrackSprite(item.width, item.height);
+ sprite = this.createTrackSprite(item.width, item.height, item.trackMask);
sprite._kind = 'crn-track';
if (this.getDeviceNo(value) > 0) { this.dualCrnList.push(item); }
} else if (item.type == 'rgv') {
- sprite = this.createTrackSprite(item.width, item.height);
+ sprite = this.createTrackSprite(item.width, item.height, item.trackMask);
sprite._kind = 'rgv-track';
if (this.getDeviceNo(value) > 0) { this.rgvList.push(item); }
} else {
@@ -1066,6 +1121,159 @@
sprite.position.set(item.posX, item.posY);
return sprite;
},
+ collectTrackItem(item) {
+ const value = item.value;
+ if (item.type === 'crn') {
+ if (this.getDeviceNo(value) > 0) { this.crnList.push(item); }
+ } else if (item.type === 'dualCrn') {
+ if (this.getDeviceNo(value) > 0) { this.dualCrnList.push(item); }
+ } else if (item.type === 'rgv') {
+ if (this.getDeviceNo(value) > 0) { this.rgvList.push(item); }
+ }
+ },
+ isTrackType(cell) {
+ return cell && (cell.type === 'crn' || cell.type === 'dualCrn' || cell.type === 'rgv');
+ },
+ resolveMergedCell(map, rowIndex, colIndex) {
+ if (!map || rowIndex < 0 || colIndex < 0) { return null; }
+ const row = map[rowIndex];
+ if (!row || colIndex >= row.length) { return null; }
+ const cell = row[colIndex];
+ if (!cell) { return null; }
+ if (!cell.isMergedPart && cell.type !== 'merge') { return cell; }
+ if (cell.isMergedPart) {
+ for (let c = colIndex - 1; c >= 0; c--) {
+ const left = row[c];
+ if (!left) { continue; }
+ if (!left.isMergedPart && left.type !== 'merge' && left.posX === cell.posX) { return left; }
+ }
+ }
+ if (cell.type === 'merge') {
+ for (let r = rowIndex - 1; r >= 0; r--) {
+ const upRow = map[r];
+ if (!upRow || colIndex >= upRow.length) { continue; }
+ const up = upRow[colIndex];
+ if (!up) { continue; }
+ if (up.type !== 'merge') { return up; }
+ }
+ }
+ return null;
+ },
+ getTrackMask(map, rowIndex, colIndex) {
+ const TRACK_N = 1;
+ const TRACK_E = 2;
+ const TRACK_S = 4;
+ const TRACK_W = 8;
+ const baseRow = map[rowIndex];
+ if (!baseRow) { return 0; }
+ const base = baseRow[colIndex];
+ if (!this.isTrackType(base)) { return 0; }
+ const rowSpan = base.rowSpan || 1;
+ const colSpan = base.colSpan || 1;
+ let mask = 0;
+ const n = this.resolveMergedCell(map, rowIndex - 1, colIndex);
+ const s = this.resolveMergedCell(map, rowIndex + rowSpan, colIndex);
+ const w = this.resolveMergedCell(map, rowIndex, colIndex - 1);
+ const e = this.resolveMergedCell(map, rowIndex, colIndex + colSpan);
+ if (n && n !== base && this.isTrackType(n)) { mask |= TRACK_N; }
+ if (e && e !== base && this.isTrackType(e)) { mask |= TRACK_E; }
+ if (s && s !== base && this.isTrackType(s)) { mask |= TRACK_S; }
+ if (w && w !== base && this.isTrackType(w)) { mask |= TRACK_W; }
+ if (mask === 0) { mask = TRACK_E | TRACK_W; }
+ return mask;
+ },
+ drawTracks(map) {
+ if (!this.tracksGraphics) { return; }
+ this.tracksGraphics.clear();
+ const rail = 3;
+ const color = 0x555555;
+ this.tracksGraphics.lineStyle({ width: rail, color: color, alpha: 1, cap: PIXI.LINE_CAP.ROUND, join: PIXI.LINE_JOIN.ROUND });
+ const drawn = new Set();
+ const toKey = (p) => {
+ const x = Math.round(p.x * 100) / 100;
+ const y = Math.round(p.y * 100) / 100;
+ return x + "," + y;
+ };
+ const edgeKey = (a, b) => {
+ const ka = toKey(a);
+ const kb = toKey(b);
+ return ka < kb ? (ka + "|" + kb) : (kb + "|" + ka);
+ };
+ const centerOf = (cell) => ({ x: cell.posX + cell.width / 2, y: cell.posY + cell.height / 2 });
+
+ for (let r = 0; r < map.length; r++) {
+ const row = map[r];
+ if (!row) { continue; }
+ for (let c = 0; c < row.length; c++) {
+ const cell = row[c];
+ if (!cell || cell.type === 'merge' || !this.isTrackType(cell) || cell.isMergedPart) { continue; }
+ const rowSpan = cell.rowSpan || 1;
+ const colSpan = cell.colSpan || 1;
+ const n = this.resolveMergedCell(map, r - 1, c);
+ const s = this.resolveMergedCell(map, r + rowSpan, c);
+ const w = this.resolveMergedCell(map, r, c - 1);
+ const e = this.resolveMergedCell(map, r, c + colSpan);
+ const hasN = n && this.isTrackType(n);
+ const hasE = e && this.isTrackType(e);
+ const hasS = s && this.isTrackType(s);
+ const hasW = w && this.isTrackType(w);
+ const count = (hasN ? 1 : 0) + (hasE ? 1 : 0) + (hasS ? 1 : 0) + (hasW ? 1 : 0);
+ const straight = (hasN && hasS) || (hasE && hasW);
+ if (count === 2 && !straight) {
+ const cPos = centerOf(cell);
+ let p1 = null;
+ let p2 = null;
+ if (hasN && hasE) { p1 = centerOf(n); p2 = centerOf(e); }
+ else if (hasE && hasS) { p1 = centerOf(e); p2 = centerOf(s); }
+ else if (hasS && hasW) { p1 = centerOf(s); p2 = centerOf(w); }
+ else if (hasW && hasN) { p1 = centerOf(w); p2 = centerOf(n); }
+ if (p1 && p2) {
+ const k1 = edgeKey(cPos, p1);
+ const k2 = edgeKey(cPos, p2);
+ if (!drawn.has(k1) || !drawn.has(k2)) {
+ this.tracksGraphics.moveTo(p1.x, p1.y);
+ this.tracksGraphics.lineTo(cPos.x, cPos.y);
+ this.tracksGraphics.lineTo(p2.x, p2.y);
+ }
+ drawn.add(k1);
+ drawn.add(k2);
+ }
+ }
+ }
+ }
+
+ for (let r = 0; r < map.length; r++) {
+ const row = map[r];
+ if (!row) { continue; }
+ for (let c = 0; c < row.length; c++) {
+ const cell = row[c];
+ if (!cell || cell.type === 'merge' || !this.isTrackType(cell) || cell.isMergedPart) { continue; }
+ const cPos = centerOf(cell);
+ const rowSpan = cell.rowSpan || 1;
+ const colSpan = cell.colSpan || 1;
+ const e = this.resolveMergedCell(map, r, c + colSpan);
+ const s = this.resolveMergedCell(map, r + rowSpan, c);
+ if (e && this.isTrackType(e)) {
+ const p = centerOf(e);
+ const k = edgeKey(cPos, p);
+ if (!drawn.has(k)) {
+ this.tracksGraphics.moveTo(cPos.x, cPos.y);
+ this.tracksGraphics.lineTo(p.x, p.y);
+ drawn.add(k);
+ }
+ }
+ if (s && this.isTrackType(s)) {
+ const p = centerOf(s);
+ const k = edgeKey(cPos, p);
+ if (!drawn.has(k)) {
+ this.tracksGraphics.moveTo(cPos.x, cPos.y);
+ this.tracksGraphics.lineTo(p.x, p.y);
+ drawn.add(k);
+ }
+ }
+ }
+ }
+ },
updateColor(sprite, color) {
if (sprite && sprite._kind === 'devp') {
const key = sprite.width + '-' + sprite.height + '-' + color;
--
Gitblit v1.9.1