diff --git a/.env b/.env index b4467e5..13a83d9 100644 --- a/.env +++ b/.env @@ -1,6 +1,10 @@ # VUE_APP_API_URL=http://31.129.106.67:8080 # VUE_APP_GEO_URL=http://31.129.106.67:6001 # VUE_APP_WEATHER_URL=http://31.129.106.67:6002 + VUE_APP_API_URL=http://127.0.0.1:8080 VUE_APP_GEO_URL=http://127.0.0.1:6001 -VUE_APP_WEATHER_URL=http://127.0.0.1:6002 \ No newline at end of file +VUE_APP_WEATHER_URL=http://127.0.0.1:6002 + +VUE_APP_VIDEO_TIMEOUT=120000 +VUE_APP_TRACKING_TIMEOUT=15000 \ No newline at end of file diff --git a/src/assets/style/main.css b/src/assets/style/main.css index 84a1035..70067b8 100644 --- a/src/assets/style/main.css +++ b/src/assets/style/main.css @@ -908,6 +908,8 @@ li.checked { word-wrap: break-word; word-break: break-word; hyphens: auto; + max-height: 51px; + overflow-y: auto; } .sight-letter { diff --git a/src/components/main.vue b/src/components/main.vue index a469c09..35fea4e 100644 --- a/src/components/main.vue +++ b/src/components/main.vue @@ -26,7 +26,7 @@ import * as PIXI from "pixi.js"; import { Viewport } from "pixi-viewport"; import { Text, TextStyle, FillGradient, Assets } from "pixi.js"; -import { API_URL, GEO_URL } from "../config"; +import { API_URL, GEO_URL, VIDEO_TIMEOUT, TRACKING_TIMEOUT } from "../config"; import sightIcon from "../icons/sight.svg"; import tramRight from "../icons/tram-right.svg"; import tramLeft from "../icons/tram-left.svg"; @@ -77,7 +77,6 @@ export default { isFollowingTram: false, followTramTimer: null, chooseTramDirection(canvasPt) { - // canvasPt: [x, y] in PIXI coords let bestDir = "right"; let bestScore = Infinity; const candidates = arrowTransforms; @@ -153,7 +152,7 @@ export default { startInactivityCheck() { if (this.inactivityInterval) return; this.inactivityInterval = setInterval(() => { - if (Date.now() - this.lastActivityTime >= 120000) { + if (Date.now() - this.lastActivityTime >= VIDEO_TIMEOUT) { this.showNearestSightVideo(); } }, 1000); @@ -335,7 +334,7 @@ export default { const minLng = Math.min(...lngs); const padding = 40; - const scale = 35000; + const scale = 50000; const midLat = (minLat + maxLat) / 2; const latFactor = Math.cos((midLat * Math.PI) / 180); console.log( @@ -360,6 +359,17 @@ export default { this.routeGraphics.stroke(); }, + // Calculate PIXI anchor based on the direction of the label offset + getAnchorFromOffset(offsetX, offsetY) { + if (offsetX === 0 && offsetY === 0) { + return { x: 0.5, y: 0.5 }; + } + const length = Math.hypot(offsetX, offsetY) || 1; + const nx = offsetX / length / 1.5; + const ny = offsetY / length; + return { x: (1 - nx) / 2, y: (1 - ny) / 2 }; + }, + // Отрисовываем станции: PIXI-кружок + подпись (RU+EN) drawStations(stationsRu, stationsEn) { console.groupCollapsed( @@ -457,80 +467,40 @@ export default { labelGroup._oy = oy; node.addChild(labelGroup); - const stationPoint = { x, y }; - const thresholdX = 15; - const thresholdY = 30; - let shiftX = 0, - shiftY = 0; - if (this.routeLatlngs && this.routeLatlngs.length > 1) { - for (let i = 0; i < this.routeLatlngs.length - 1; i++) { - const p1 = this.toCanvasPoint(this.routeLatlngs[i]); - const p2 = this.toCanvasPoint(this.routeLatlngs[i + 1]); - const vx = p2.x - p1.x, - vy = p2.y - p1.y; - const len2 = vx * vx + vy * vy; - const t = - ((stationPoint.x - p1.x) * vx + (stationPoint.y - p1.y) * vy) / - (len2 || 1); - const tClamped = Math.max(0, Math.min(1, t)); - const projX = p1.x + vx * tClamped; - const projY = p1.y + vy * tClamped; - const dx = stationPoint.x - projX, - dy = stationPoint.y - projY; - // elliptical distance check - const normDist = - (dx * dx) / (thresholdX * thresholdX) + - (dy * dy) / (thresholdY * thresholdY); - if (normDist < 1) { - // compute normal to segment - let nx = -vy, - ny = vx; - const nlen = Math.hypot(nx, ny) || 1; - nx /= nlen; - ny /= nlen; - // choose direction based on original offset - const dot = ox * nx + oy * ny; - const sign = dot >= 0 ? 1 : -1; - shiftX = nx * thresholdX * sign; - shiftY = ny * thresholdY * sign; - break; - } - } - } - // apply shift - labelGroup.x += shiftX; - labelGroup.y += shiftY; - labelGroup._ox += shiftX; - labelGroup._oy += shiftY; + let shiftX = 0; + let shiftY = 0; + + const offX = ox + shiftX; + const offY = oy + shiftY; + // Anchor that depends on the final offset direction + const anchor = this.getAnchorFromOffset(offX, offY); - // RU const ruStyle = new TextStyle({ fill: solidWhite, fontSize: 20, fontFamily: "Arial", - align: "right", fontWeight: "bold", }); const ruText = new Text({ text: st.name, style: ruStyle }); - ruText.anchor.set(1, 0.5); // bottom-right - ruText.x = 24; - ruText.y = -35; + ruText.anchor.set(anchor.x, anchor.y); + ruText.x = 0; + ruText.y = 0; labelGroup.addChild(ruText); - // EN + // ── EN name (optional) ── const enName = enById[st.id]; if (enName) { const enStyle = new TextStyle({ fill: lightGray, fontSize: 12, fontFamily: "Arial", - align: "right", fontWeight: "bold", }); const enText = new Text({ text: enName, style: enStyle }); - enText.anchor.set(1, -1); // top-right - enText.x = 24; - enText.y = ruText.y + 2; + enText.anchor.set(anchor.x, anchor.y); + const verticalDir = oy + shiftY >= 0 ? 1 : -1; + enText.x = 0; + enText.y = verticalDir * (ruText.height + 2); labelGroup.addChild(enText); } @@ -1089,7 +1059,7 @@ export default { this.inactivityTimer = setTimeout(() => { this.isFollowingTram = true; this.startFollowTram(); - }, 15000); + }, TRACKING_TIMEOUT); }, startFollowTram() { diff --git a/src/config.js b/src/config.js index 9675a6b..ece8a3d 100644 --- a/src/config.js +++ b/src/config.js @@ -1,3 +1,5 @@ export const API_URL = process.env.VUE_APP_API_URL; export const GEO_URL = process.env.VUE_APP_GEO_URL; export const WEATHER_URL = process.env.VUE_APP_WEATHER_URL; +export const VIDEO_TIMEOUT = process.env.VUE_APP_VIDEO_TIMEOUT || 120000; +export const TRACKING_TIMEOUT = process.env.VUE_APP_TRACKING_TIMEOUT || 15000;