feat(web): 优化车站名与线路名显示,增加车站编号与英文名称

This commit is contained in:
2026-07-12 10:04:40 +08:00
parent 423a5972fc
commit 46f8a17157
4 changed files with 71 additions and 20 deletions
+2 -2
View File
@@ -16,8 +16,8 @@
"mtimeMs": 1783602619602.658 "mtimeMs": 1783602619602.658
}, },
"ticket-order.js": { "ticket-order.js": {
"size": 37477, "size": 40778,
"mtimeMs": 1783820973442.9248 "mtimeMs": 1783821841376.1682
}, },
"ticket-search.js": { "ticket-search.js": {
"size": 17269, "size": 17269,
+1 -1
View File
@@ -3,7 +3,7 @@
"blog.css": 2, "blog.css": 2,
"custom-dialog.js": 11, "custom-dialog.js": 11,
"public-status.js": 14, "public-status.js": 14,
"ticket-order.js": 25, "ticket-order.js": 26,
"ticket-search.js": 12, "ticket-search.js": 12,
"ticket-route.js": 3, "ticket-route.js": 3,
"index.js": 5, "index.js": 5,
+1 -1
View File
@@ -158,7 +158,7 @@
</div> </div>
<script src="/custom-dialog.js?v=11"></script> <script src="/custom-dialog.js?v=11"></script>
<script src="/ticket-order.js?v=25"></script> <script src="/ticket-order.js?v=26"></script>
<script src="/public-status.js?v=14"></script> <script src="/public-status.js?v=14"></script>
<script> <script>
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
+67 -16
View File
@@ -215,7 +215,7 @@
for (const c of stops) { for (const c of stops) {
if (c === '-') { if (c === '-') {
if (currentSegment.length > 0) { if (currentSegment.length > 0) {
lineStops.push({ idx: currentLineIdx, name: line.name || line.线路名称 || '', color, stops: currentSegment }); lineStops.push({ idx: currentLineIdx, name: line.name || line.线路名称 || '', enName: line.en_name || line.英文名称 || line.英文名 || '', color, stops: currentSegment });
lineColors.push(color); lineColors.push(color);
for (const stopCode of currentSegment) { for (const stopCode of currentSegment) {
const arr = linesByStation.get(stopCode) || []; const arr = linesByStation.get(stopCode) || [];
@@ -233,7 +233,7 @@
} }
} }
if (currentSegment.length > 0) { if (currentSegment.length > 0) {
lineStops.push({ idx: currentLineIdx, name: line.name || line.线路名称 || '', color, stops: currentSegment }); lineStops.push({ idx: currentLineIdx, name: line.name || line.线路名称 || '', enName: line.en_name || line.英文名称 || line.英文名 || '', color, stops: currentSegment });
lineColors.push(color); lineColors.push(color);
for (const stopCode of currentSegment) { for (const stopCode of currentSegment) {
const arr = linesByStation.get(stopCode) || []; const arr = linesByStation.get(stopCode) || [];
@@ -332,13 +332,15 @@
} }
const labelPlacements = {}; const labelPlacements = {};
const placeLabel = (x, y, isStart, name, color) => { const placeLabel = (x, y, isStart, name, enName, color) => {
const key = `${x},${y},${isStart ? 'left' : 'right'}`; const key = `${x},${y},${isStart ? 'left' : 'right'}`;
const count = labelPlacements[key] || 0; const count = labelPlacements[key] || 0;
labelPlacements[key] = count + 1; labelPlacements[key] = count + 1;
const nameLen = name.length * 13 + 16; const hasEn = !!enName;
const yOffset = count * 30 - 12; // stack vertically, center on point initially const nameLen = Math.max(name.length * 13 + 16, hasEn ? enName.length * 6.5 + 16 : 0);
const h = hasEn ? 36 : 24;
const yOffset = count * 42 - (h / 2);
let lx, textX; let lx, textX;
if (isStart) { if (isStart) {
@@ -349,8 +351,14 @@
textX = lx + nameLen / 2; textX = lx + nameLen / 2;
} }
return `<rect x="${lx}" y="${y + yOffset}" width="${nameLen}" height="24" rx="12" fill="${color}" />` + let svg = `<rect x="${lx}" y="${y + yOffset}" width="${nameLen}" height="${h}" rx="6" fill="${color}" />`;
`<text x="${textX}" y="${y + yOffset + 16}" text-anchor="middle" fill="#fff" font-size="12" font-weight="bold">${name}</text>`; if (hasEn) {
svg += `<text x="${textX}" y="${y + yOffset + 15}" text-anchor="middle" fill="#fff" font-size="12" font-weight="bold">${name}</text>`;
svg += `<text x="${textX}" y="${y + yOffset + 28}" text-anchor="middle" fill="rgba(255,255,255,0.9)" font-size="9" font-weight="600">${enName}</text>`;
} else {
svg += `<text x="${textX}" y="${y + yOffset + 16}" text-anchor="middle" fill="#fff" font-size="12" font-weight="bold">${name}</text>`;
}
return svg;
}; };
let svgContent = ''; let svgContent = '';
@@ -371,8 +379,8 @@
// Add line name labels at ends // Add line name labels at ends
const pStart = pts[0]; const pStart = pts[0];
const pEnd = pts[pts.length - 1]; const pEnd = pts[pts.length - 1];
svgContent += placeLabel(pStart.x, pStart.y, true, li.name, li.color); svgContent += placeLabel(pStart.x, pStart.y, true, li.name, li.enName, li.color);
svgContent += placeLabel(pEnd.x, pEnd.y, false, li.name, li.color); svgContent += placeLabel(pEnd.x, pEnd.y, false, li.name, li.enName, li.color);
} }
} }
@@ -389,6 +397,9 @@
const isTransfer = uniqueColors.length >= 2 || codes.length >= 2; const isTransfer = uniqueColors.length >= 2 || codes.length >= 2;
const name = getStationDisplayName(primaryCode); const name = getStationDisplayName(primaryCode);
const enName = stationEnByCode[primaryCode] || '';
const showEn = !!enName;
let markerSvg = ''; let markerSvg = '';
if (isTransfer) { if (isTransfer) {
markerSvg += `<circle cx="${x}" cy="${y}" r="15" fill="#ffffff" stroke="#1f2937" stroke-width="2.5" />`; markerSvg += `<circle cx="${x}" cy="${y}" r="15" fill="#ffffff" stroke="#1f2937" stroke-width="2.5" />`;
@@ -401,17 +412,57 @@
} }
const preferTop = isTransfer || (i % 2 === 0 && y >= baseY + 20); const preferTop = isTransfer || (i % 2 === 0 && y >= baseY + 20);
const labelY = preferTop ? (y - 22) : (y + 30);
const labelClass = preferTop ? 'station-label-top' : 'station-label-bottom';
let labelSvg = ''; let labelSvg = '';
let textContent = '';
const codeFontSize = 9;
const nameFontSize = 13;
const enFontSize = 8.5;
const codeW = primaryCode.length * 6 + 10;
if (preferTop) {
const bottomY = y - 14;
const enY = bottomY;
const nameY = showEn ? bottomY - 12 : bottomY;
const codeY = nameY - 16;
if (isTransfer) { if (isTransfer) {
const labelW = Math.max(72, name.length * 14 + 18); const labelW = Math.max(72, name.length * 14 + 18, codeW + 16, showEn ? enName.length * 5.5 + 16 : 0);
labelSvg += `<rect x="${x - labelW / 2}" y="${labelY - 16}" width="${labelW}" height="24" rx="12" fill="rgba(248,250,252,0.96)" stroke="#cbd5e1" stroke-width="1.5" />`; const labelH = showEn ? 46 : 34;
labelSvg += `<text class="${labelClass}" x="${x}" y="${labelY}" text-anchor="middle" fill="#334155" font-size="13" font-weight="800">${name}</text>`; const rectY = codeY - 10;
} else { labelSvg += `<rect x="${x - labelW / 2}" y="${rectY}" width="${labelW}" height="${labelH}" rx="6" fill="rgba(255,255,255,0.95)" stroke="#cbd5e1" stroke-width="1.5" />`;
labelSvg += `<text class="${labelClass}" x="${x}" y="${labelY}" text-anchor="middle" fill="#334155" font-size="13.5" font-weight="700">${name}</text>`;
} }
textContent += `<rect x="${x - codeW / 2}" y="${codeY - 8}" width="${codeW}" height="12" rx="3" fill="#f1f5f9" stroke="#cbd5e1" stroke-width="1" />`;
textContent += `<text x="${x}" y="${codeY + 1}" text-anchor="middle" fill="#475569" font-size="${codeFontSize}" font-weight="700" letter-spacing="0.02em">${primaryCode}</text>`;
textContent += `<text x="${x}" y="${nameY}" text-anchor="middle" fill="#334155" font-size="${nameFontSize}" font-weight="${isTransfer ? 800 : 700}">${name}</text>`;
if (showEn) {
textContent += `<text x="${x}" y="${enY}" text-anchor="middle" fill="#94a3b8" font-size="${enFontSize}" font-weight="600">${enName}</text>`;
}
} else {
const topY = y + 24;
const codeY = topY;
const nameY = topY + 16;
const enY = nameY + 12;
if (isTransfer) {
const labelW = Math.max(72, name.length * 14 + 18, codeW + 16, showEn ? enName.length * 5.5 + 16 : 0);
const labelH = showEn ? 46 : 34;
const rectY = codeY - 10;
labelSvg += `<rect x="${x - labelW / 2}" y="${rectY}" width="${labelW}" height="${labelH}" rx="6" fill="rgba(255,255,255,0.95)" stroke="#cbd5e1" stroke-width="1.5" />`;
}
textContent += `<rect x="${x - codeW / 2}" y="${codeY - 8}" width="${codeW}" height="12" rx="3" fill="#f1f5f9" stroke="#cbd5e1" stroke-width="1" />`;
textContent += `<text x="${x}" y="${codeY + 1}" text-anchor="middle" fill="#475569" font-size="${codeFontSize}" font-weight="700" letter-spacing="0.02em">${primaryCode}</text>`;
textContent += `<text x="${x}" y="${nameY}" text-anchor="middle" fill="#334155" font-size="${nameFontSize}" font-weight="${isTransfer ? 800 : 700}">${name}</text>`;
if (showEn) {
textContent += `<text x="${x}" y="${enY}" text-anchor="middle" fill="#94a3b8" font-size="${enFontSize}" font-weight="600">${enName}</text>`;
}
}
labelSvg += textContent;
svgContent += ` svgContent += `
<g class="map-station ${isTransfer ? 'transfer' : ''}" data-code="${primaryCode}" data-canonical="${canonical}" onclick="handleStationClick('${primaryCode}')" style="cursor:pointer"> <g class="map-station ${isTransfer ? 'transfer' : ''}" data-code="${primaryCode}" data-canonical="${canonical}" onclick="handleStationClick('${primaryCode}')" style="cursor:pointer">
<rect x="${x - 20}" y="${y - 20}" width="40" height="40" fill="transparent" /> <rect x="${x - 20}" y="${y - 20}" width="40" height="40" fill="transparent" />