feat(web): 回退到以发散方式显示各条水平线路
This commit is contained in:
@@ -16,8 +16,8 @@
|
|||||||
"mtimeMs": 1783602619602.658
|
"mtimeMs": 1783602619602.658
|
||||||
},
|
},
|
||||||
"ticket-order.js": {
|
"ticket-order.js": {
|
||||||
"size": 41045,
|
"size": 37721,
|
||||||
"mtimeMs": 1783829841573.1077
|
"mtimeMs": 1783947073044.0798
|
||||||
},
|
},
|
||||||
"ticket-search.js": {
|
"ticket-search.js": {
|
||||||
"size": 17269,
|
"size": 17269,
|
||||||
|
|||||||
@@ -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": 29,
|
"ticket-order.js": 30,
|
||||||
"ticket-search.js": 12,
|
"ticket-search.js": 12,
|
||||||
"ticket-route.js": 3,
|
"ticket-route.js": 3,
|
||||||
"index.js": 5,
|
"index.js": 5,
|
||||||
|
|||||||
@@ -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=29"></script>
|
<script src="/ticket-order.js?v=30"></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', () => {
|
||||||
|
|||||||
+30
-118
@@ -59,79 +59,9 @@
|
|||||||
if (!points || points.length === 0) return '';
|
if (!points || points.length === 0) return '';
|
||||||
if (points.length === 1) return `M ${points[0].x} ${points[0].y}`;
|
if (points.length === 1) return `M ${points[0].x} ${points[0].y}`;
|
||||||
|
|
||||||
const expanded = [points[0]];
|
let d = `M ${points[0].x} ${points[0].y}`;
|
||||||
for (let i = 1; i < points.length; i++) {
|
for (let i = 1; i < points.length; i++) {
|
||||||
const prev = points[i - 1];
|
d += ` L ${points[i].x} ${points[i].y}`;
|
||||||
const cur = points[i];
|
|
||||||
const dx = cur.x - prev.x;
|
|
||||||
const dy = cur.y - prev.y;
|
|
||||||
|
|
||||||
if (dx === 0 || dy === 0 || Math.abs(dx) === Math.abs(dy)) {
|
|
||||||
expanded.push(cur);
|
|
||||||
} else {
|
|
||||||
const absDx = Math.abs(dx);
|
|
||||||
const absDy = Math.abs(dy);
|
|
||||||
if (absDx > absDy) {
|
|
||||||
const signX = Math.sign(dx);
|
|
||||||
const straightLen = absDx - absDy;
|
|
||||||
expanded.push({ x: prev.x + signX * (straightLen / 2), y: prev.y });
|
|
||||||
expanded.push({ x: cur.x - signX * (straightLen / 2), y: cur.y });
|
|
||||||
expanded.push(cur);
|
|
||||||
} else {
|
|
||||||
const signY = Math.sign(dy);
|
|
||||||
const straightLen = absDy - absDx;
|
|
||||||
expanded.push({ x: prev.x, y: prev.y + signY * (straightLen / 2) });
|
|
||||||
expanded.push({ x: cur.x, y: cur.y - signY * (straightLen / 2) });
|
|
||||||
expanded.push(cur);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const cleaned = [expanded[0]];
|
|
||||||
for (let i = 1; i < expanded.length; i++) {
|
|
||||||
const last = cleaned[cleaned.length - 1];
|
|
||||||
const p = expanded[i];
|
|
||||||
if (Math.abs(last.x - p.x) > 0.1 || Math.abs(last.y - p.y) > 0.1) {
|
|
||||||
cleaned.push(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let d = `M ${cleaned[0].x} ${cleaned[0].y}`;
|
|
||||||
for (let i = 1; i < cleaned.length; i++) {
|
|
||||||
const prev = cleaned[i - 1];
|
|
||||||
const cur = cleaned[i];
|
|
||||||
const next = cleaned[i + 1];
|
|
||||||
|
|
||||||
if (!next) {
|
|
||||||
d += ` L ${cur.x} ${cur.y}`;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dx1 = cur.x - prev.x;
|
|
||||||
const dy1 = cur.y - prev.y;
|
|
||||||
const len1 = Math.sqrt(dx1*dx1 + dy1*dy1);
|
|
||||||
const dx2 = next.x - cur.x;
|
|
||||||
const dy2 = next.y - cur.y;
|
|
||||||
const len2 = Math.sqrt(dx2*dx2 + dy2*dy2);
|
|
||||||
|
|
||||||
if (len1 < 0.1 || len2 < 0.1) {
|
|
||||||
d += ` L ${cur.x} ${cur.y}`;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cross = dx1 * dy2 - dy1 * dx2;
|
|
||||||
if (Math.abs(cross) < 0.1) {
|
|
||||||
d += ` L ${cur.x} ${cur.y}`;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const r = Math.min(radius, len1 / 2, len2 / 2);
|
|
||||||
const startX = cur.x - (dx1 / len1) * r;
|
|
||||||
const startY = cur.y - (dy1 / len1) * r;
|
|
||||||
const endX = cur.x + (dx2 / len2) * r;
|
|
||||||
const endY = cur.y + (dy2 / len2) * r;
|
|
||||||
|
|
||||||
d += ` L ${startX} ${startY} Q ${cur.x} ${cur.y} ${endX} ${endY}`;
|
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
};
|
};
|
||||||
@@ -264,59 +194,41 @@
|
|||||||
const legendW = 10;
|
const legendW = 10;
|
||||||
const startX = 140;
|
const startX = 140;
|
||||||
const baseY = 80;
|
const baseY = 80;
|
||||||
const lineGapY = 64;
|
const lineGapY = 80;
|
||||||
const gridScaleX = 96;
|
const minGapX = 80;
|
||||||
|
|
||||||
// 1. Assign base Y to lines
|
const occurrences = {};
|
||||||
const lineBaseY = {};
|
|
||||||
for (let i = 0; i < lineStops.length; i++) {
|
|
||||||
lineBaseY[lineStops[i].idx] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Assign Grid X to canonical stations (Topological / Depth based)
|
|
||||||
const stationGridX = {};
|
|
||||||
for (const li of lineStops) {
|
for (const li of lineStops) {
|
||||||
li.stops.forEach((code, idx) => {
|
for (let i = 0; i < li.stops.length; i++) {
|
||||||
if (code === '-') return;
|
const code = li.stops[i];
|
||||||
|
if (code === '-') continue;
|
||||||
const canonical = stationCanonicalByCode[code] || code;
|
const canonical = stationCanonicalByCode[code] || code;
|
||||||
if (stationGridX[canonical] == null) {
|
if (!occurrences[canonical]) occurrences[canonical] = [];
|
||||||
stationGridX[canonical] = idx;
|
occurrences[canonical].push(i * minGapX);
|
||||||
} else {
|
|
||||||
stationGridX[canonical] = Math.max(stationGridX[canonical], idx);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Relax Grid X to ensure connections always move forward (minimum 1 unit gap)
|
|
||||||
let changed = true;
|
|
||||||
let passes = 0;
|
|
||||||
while (changed && passes < 100) {
|
|
||||||
changed = false;
|
|
||||||
passes++;
|
|
||||||
for (const li of lineStops) {
|
|
||||||
let prevCanonical = null;
|
|
||||||
for (const code of li.stops) {
|
|
||||||
if (code === '-') {
|
|
||||||
prevCanonical = null;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const canonical = stationCanonicalByCode[code] || code;
|
|
||||||
if (prevCanonical) {
|
|
||||||
// Extra spacing if either is a transfer station to avoid crowding
|
|
||||||
const needExtra = (lineIdxsByCanonical[canonical]?.size >= 2 || lineIdxsByCanonical[prevCanonical]?.size >= 2) ? 1.5 : 1;
|
|
||||||
if (stationGridX[canonical] < stationGridX[prevCanonical] + needExtra) {
|
|
||||||
stationGridX[canonical] = stationGridX[prevCanonical] + needExtra;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prevCanonical = canonical;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stationXByCanonical = {};
|
stationXByCanonical = {};
|
||||||
for (const canonical of Object.keys(stationGridX)) {
|
for (const canonical of Object.keys(occurrences)) {
|
||||||
stationXByCanonical[canonical] = startX + stationGridX[canonical] * gridScaleX;
|
const arr = occurrences[canonical];
|
||||||
|
const avg = arr.reduce((a,b)=>a+b,0) / Math.max(1, arr.length);
|
||||||
|
stationXByCanonical[canonical] = startX + Math.round(avg);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let pass = 0; pass < 3; pass++) {
|
||||||
|
for (const li of lineStops) {
|
||||||
|
let prevX = startX - minGapX;
|
||||||
|
for (const code of li.stops) {
|
||||||
|
if (code === '-') continue;
|
||||||
|
const canonical = stationCanonicalByCode[code] || code;
|
||||||
|
const x = stationXByCanonical[canonical] ?? (prevX + minGapX);
|
||||||
|
const nx = Math.max(x, prevX + minGapX);
|
||||||
|
if (stationXByCanonical[canonical] == null || nx > stationXByCanonical[canonical]) {
|
||||||
|
stationXByCanonical[canonical] = nx;
|
||||||
|
}
|
||||||
|
prevX = stationXByCanonical[canonical];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Assign Grid Y to canonical stations (Average of their lines)
|
// 3. Assign Grid Y to canonical stations (Average of their lines)
|
||||||
|
|||||||
Reference in New Issue
Block a user