| | |
| | | <div style="position: absolute; top: 20px; right: 50px; text-align: right;"> |
| | | <div>FPS:{{mapFps}}</div> |
| | | <div style="margin-top: 6px; display: flex; gap: 6px; justify-content: flex-end;"> |
| | | <button type="button" @click="toggleStationDirection" style="padding: 2px 8px; font-size: 12px; cursor: pointer;">{{ showStationDirection ? '隐藏站点方向' : '显示站点方向' }}</button> |
| | | <button type="button" @click="rotateMap" style="padding: 2px 8px; font-size: 12px; cursor: pointer;">旋转</button> |
| | | <button type="button" @click="toggleMirror" style="padding: 2px 8px; font-size: 12px; cursor: pointer;">{{ mapMirrorX ? '取消镜像' : '镜像' }}</button> |
| | | </div> |
| | |
| | | taskStationCount: 0, |
| | | currentLoad: 0 |
| | | }, |
| | | showStationDirection: false, |
| | | hoverLoopNo: null, |
| | | hoverLoopStationIdSet: new Set(), |
| | | loopHighlightColor: 0xfff34d |
| | | loopHighlightColor: 0xfff34d, |
| | | stationDirectionColor: 0xff5a36 |
| | | } |
| | | }, |
| | | mounted() { |
| | |
| | | } |
| | | } |
| | | xCursor += cellWidth; |
| | | } |
| | | }); |
| | | |
| | | map.forEach((row, rowIndex) => { |
| | | for (let colIndex = 0; colIndex < row.length; colIndex++) { |
| | | const val = row[colIndex]; |
| | | if (!val || val.type !== 'devp' || val.type === 'merge') { continue; } |
| | | val.stationDirectionList = this.resolveStationDirectionList(map, rowIndex, colIndex, val); |
| | | } |
| | | }); |
| | | |
| | |
| | | } |
| | | sprite = new PIXI.Sprite(texture); |
| | | sprite._kind = 'devp'; |
| | | const directionOverlay = this.createStationDirectionOverlay(item.width, item.height, item.stationDirectionList); |
| | | if (directionOverlay) { |
| | | directionOverlay.visible = this.showStationDirection; |
| | | sprite.addChild(directionOverlay); |
| | | } |
| | | sprite.directionObj = directionOverlay; |
| | | sprite._stationDirectionList = Array.isArray(item.stationDirectionList) ? item.stationDirectionList.slice() : []; |
| | | let siteId = this.getStationId(value); |
| | | if (siteId === -1) { siteId = item.data; } |
| | | const style = new PIXI.TextStyle({ fontFamily: 'Arial', fontSize: 10, fill: '#000000', stroke: '#ffffff', strokeThickness: 1 }); |
| | |
| | | }, |
| | | getStationId(obj) { |
| | | if (this.isJson(obj)) { let data = JSON.parse(obj); if (data.stationId == null || data.stationId == undefined) { return -1; } return data.stationId; } else { return -1; } |
| | | }, |
| | | parseMapValue(obj) { |
| | | if (obj == null) { return null; } |
| | | if (typeof obj === 'object') { return obj; } |
| | | if (!this.isJson(obj)) { return null; } |
| | | try { |
| | | return JSON.parse(obj); |
| | | } catch (e) { |
| | | return null; |
| | | } |
| | | }, |
| | | normalizeDirectionList(direction) { |
| | | const aliasMap = { |
| | | top: 'top', |
| | | up: 'top', |
| | | north: 'top', |
| | | bottom: 'bottom', |
| | | down: 'bottom', |
| | | south: 'bottom', |
| | | left: 'left', |
| | | west: 'left', |
| | | right: 'right', |
| | | east: 'right' |
| | | }; |
| | | let rawList = []; |
| | | if (Array.isArray(direction)) { |
| | | rawList = direction; |
| | | } else if (typeof direction === 'string') { |
| | | rawList = direction.split(/[,\s|/]+/); |
| | | } |
| | | const result = []; |
| | | const seen = new Set(); |
| | | rawList.forEach((item) => { |
| | | const key = aliasMap[String(item || '').trim().toLowerCase()]; |
| | | if (!key || seen.has(key)) { return; } |
| | | seen.add(key); |
| | | result.push(key); |
| | | }); |
| | | return result; |
| | | }, |
| | | resolveStationDirectionList(map, rowIndex, colIndex, item) { |
| | | const valueObj = this.parseMapValue(item && item.value); |
| | | const fromValue = this.normalizeDirectionList(valueObj && valueObj.direction); |
| | | if (fromValue.length > 0) { return fromValue; } |
| | | const rowSpan = item && item.rowSpan ? item.rowSpan : 1; |
| | | const colSpan = item && item.colSpan ? item.colSpan : 1; |
| | | const fallback = []; |
| | | const candidateList = [ |
| | | { key: 'top', cell: this.resolveMergedCell(map, rowIndex - 1, colIndex) }, |
| | | { key: 'right', cell: this.resolveMergedCell(map, rowIndex, colIndex + colSpan) }, |
| | | { key: 'bottom', cell: this.resolveMergedCell(map, rowIndex + rowSpan, colIndex) }, |
| | | { key: 'left', cell: this.resolveMergedCell(map, rowIndex, colIndex - 1) } |
| | | ]; |
| | | candidateList.forEach((candidate) => { |
| | | if (this.isStationDirectionNeighbor(candidate.cell)) { |
| | | fallback.push(candidate.key); |
| | | } |
| | | }); |
| | | return fallback; |
| | | }, |
| | | isStationDirectionNeighbor(cell) { |
| | | if (!cell) { return false; } |
| | | if (cell.type === 'devp') { return true; } |
| | | return this.isTrackType(cell); |
| | | }, |
| | | createStationDirectionOverlay(width, height, directionList) { |
| | | if (!Array.isArray(directionList) || directionList.length === 0) { return null; } |
| | | const container = new PIXI.Container(); |
| | | const arrowSize = Math.max(4, Math.min(width, height) * 0.22); |
| | | const margin = Math.max(2, Math.min(width, height) * 0.12); |
| | | directionList.forEach((direction) => { |
| | | const arrow = new PIXI.Graphics(); |
| | | this.drawStationDirectionArrow(arrow, width, height, direction, arrowSize, margin); |
| | | container.addChild(arrow); |
| | | }); |
| | | return container; |
| | | }, |
| | | drawStationDirectionArrow(graphics, width, height, direction, size, margin) { |
| | | if (!graphics) { return; } |
| | | const halfBase = Math.max(2, size * 0.45); |
| | | const stemLen = Math.max(3, size * 0.7); |
| | | const centerX = width / 2; |
| | | const centerY = height / 2; |
| | | graphics.beginFill(this.stationDirectionColor, 0.95); |
| | | if (direction === 'top') { |
| | | const tipY = margin; |
| | | const baseY = margin + size; |
| | | const stemY = Math.min(centerY - 2, baseY + stemLen); |
| | | if (stemY > baseY) { graphics.moveTo(centerX, stemY); graphics.lineTo(centerX, baseY); } |
| | | graphics.moveTo(centerX, tipY); |
| | | graphics.lineTo(centerX - halfBase, baseY); |
| | | graphics.lineTo(centerX + halfBase, baseY); |
| | | } else if (direction === 'right') { |
| | | const tipX = width - margin; |
| | | const baseX = width - margin - size; |
| | | const stemX = Math.max(centerX + 2, baseX - stemLen); |
| | | if (stemX < baseX) { graphics.moveTo(stemX, centerY); graphics.lineTo(baseX, centerY); } |
| | | graphics.moveTo(tipX, centerY); |
| | | graphics.lineTo(baseX, centerY - halfBase); |
| | | graphics.lineTo(baseX, centerY + halfBase); |
| | | } else if (direction === 'bottom') { |
| | | const tipY = height - margin; |
| | | const baseY = height - margin - size; |
| | | const stemY = Math.max(centerY + 2, baseY - stemLen); |
| | | if (stemY < baseY) { graphics.moveTo(centerX, stemY); graphics.lineTo(centerX, baseY); } |
| | | graphics.moveTo(centerX, tipY); |
| | | graphics.lineTo(centerX - halfBase, baseY); |
| | | graphics.lineTo(centerX + halfBase, baseY); |
| | | } else if (direction === 'left') { |
| | | const tipX = margin; |
| | | const baseX = margin + size; |
| | | const stemX = Math.min(centerX - 2, baseX + stemLen); |
| | | if (stemX > baseX) { graphics.moveTo(stemX, centerY); graphics.lineTo(baseX, centerY); } |
| | | graphics.moveTo(tipX, centerY); |
| | | graphics.lineTo(baseX, centerY - halfBase); |
| | | graphics.lineTo(baseX, centerY + halfBase); |
| | | } |
| | | graphics.closePath(); |
| | | graphics.endFill(); |
| | | }, |
| | | applyStationDirectionVisibility() { |
| | | if (!this.pixiStaMap) { return; } |
| | | this.pixiStaMap.forEach((sprite) => { |
| | | if (!sprite || !sprite.directionObj) { return; } |
| | | sprite.directionObj.visible = this.showStationDirection; |
| | | }); |
| | | }, |
| | | getTrackSiteNo(obj) { |
| | | if (this.isJson(obj)) { let data = JSON.parse(obj); if (data.trackSiteNo == null || data.trackSiteNo == undefined) { return -1; } return data.trackSiteNo; } else { return -1; } |
| | |
| | | this.applyMapTransform(true); |
| | | this.saveMapTransformConfig(); |
| | | }, |
| | | toggleStationDirection() { |
| | | this.showStationDirection = !this.showStationDirection; |
| | | this.applyStationDirectionVisibility(); |
| | | }, |
| | | toggleMirror() { |
| | | this.mapMirrorX = !this.mapMirrorX; |
| | | this.applyMapTransform(true); |
| | |
| | | } |
| | | } |
| | | }); |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |