refactor(web): 将订票线路图改为90度规整走线并保留圆角
This commit is contained in:
@@ -16,8 +16,8 @@
|
|||||||
"mtimeMs": 1783602619602.658
|
"mtimeMs": 1783602619602.658
|
||||||
},
|
},
|
||||||
"ticket-order.js": {
|
"ticket-order.js": {
|
||||||
"size": 33737,
|
"size": 37866,
|
||||||
"mtimeMs": 1783816412239.149
|
"mtimeMs": 1783818082616.8108
|
||||||
},
|
},
|
||||||
"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": 23,
|
"ticket-order.js": 24,
|
||||||
"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=23"></script>
|
<script src="/ticket-order.js?v=24"></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', () => {
|
||||||
|
|||||||
+114
-6
@@ -55,6 +55,117 @@
|
|||||||
return out;
|
return out;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const appendPolylinePoint = (points, x, y) => {
|
||||||
|
const px = Math.round(Number(x) || 0);
|
||||||
|
const py = Math.round(Number(y) || 0);
|
||||||
|
const last = points[points.length - 1];
|
||||||
|
if (last && last.x === px && last.y === py) return;
|
||||||
|
points.push({ x: px, y: py });
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildRoundedOrthogonalPath = (points, radius = 14) => {
|
||||||
|
if (!Array.isArray(points) || points.length === 0) return '';
|
||||||
|
if (points.length === 1) return `M ${points[0].x} ${points[0].y}`;
|
||||||
|
|
||||||
|
let d = `M ${points[0].x} ${points[0].y}`;
|
||||||
|
for (let i = 1; i < points.length; i++) {
|
||||||
|
const prev = points[i - 1];
|
||||||
|
const cur = points[i];
|
||||||
|
const next = points[i + 1];
|
||||||
|
if (!next) {
|
||||||
|
d += ` L ${cur.x} ${cur.y}`;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inDx = cur.x - prev.x;
|
||||||
|
const inDy = cur.y - prev.y;
|
||||||
|
const outDx = next.x - cur.x;
|
||||||
|
const outDy = next.y - cur.y;
|
||||||
|
const isCorner = ((inDx === 0 && outDy === 0) || (inDy === 0 && outDx === 0)) && !(inDx === 0 && outDx === 0) && !(inDy === 0 && outDy === 0);
|
||||||
|
if (!isCorner) {
|
||||||
|
d += ` L ${cur.x} ${cur.y}`;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inLen = Math.abs(inDx) + Math.abs(inDy);
|
||||||
|
const outLen = Math.abs(outDx) + Math.abs(outDy);
|
||||||
|
const r = Math.max(0, Math.min(radius, inLen / 2, outLen / 2));
|
||||||
|
const inX = cur.x - Math.sign(inDx) * r;
|
||||||
|
const inY = cur.y - Math.sign(inDy) * r;
|
||||||
|
const outX = cur.x + Math.sign(outDx) * r;
|
||||||
|
const outY = cur.y + Math.sign(outDy) * r;
|
||||||
|
d += ` L ${inX} ${inY} Q ${cur.x} ${cur.y} ${outX} ${outY}`;
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
};
|
||||||
|
|
||||||
|
function isTransferCode(code) {
|
||||||
|
const normalized = String(code || '').trim();
|
||||||
|
if (!normalized) return false;
|
||||||
|
const canonical = stationCanonicalByCode[normalized] || normalized;
|
||||||
|
const codes = stationCodesByCanonical[canonical] || [];
|
||||||
|
return codes.length >= 2 || stationTransfer.has(normalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildLinePath(points, yLine) {
|
||||||
|
if (!Array.isArray(points) || points.length === 0) return '';
|
||||||
|
const poly = [];
|
||||||
|
appendPolylinePoint(poly, points[0].x, points[0].y);
|
||||||
|
for (let i = 1; i < points.length; i++) {
|
||||||
|
const prev = points[i - 1];
|
||||||
|
const cur = points[i];
|
||||||
|
const prevOnLine = Math.abs(prev.y - yLine) < 0.5;
|
||||||
|
const curOnLine = Math.abs(cur.y - yLine) < 0.5;
|
||||||
|
|
||||||
|
if (prev.x === cur.x || prev.y === cur.y) {
|
||||||
|
appendPolylinePoint(poly, cur.x, cur.y);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevOnLine && curOnLine) {
|
||||||
|
appendPolylinePoint(poly, cur.x, cur.y);
|
||||||
|
} else if (prevOnLine && !curOnLine) {
|
||||||
|
appendPolylinePoint(poly, cur.x, yLine);
|
||||||
|
appendPolylinePoint(poly, cur.x, cur.y);
|
||||||
|
} else if (!prevOnLine && curOnLine) {
|
||||||
|
appendPolylinePoint(poly, prev.x, yLine);
|
||||||
|
appendPolylinePoint(poly, cur.x, cur.y);
|
||||||
|
} else {
|
||||||
|
appendPolylinePoint(poly, prev.x, yLine);
|
||||||
|
appendPolylinePoint(poly, cur.x, yLine);
|
||||||
|
appendPolylinePoint(poly, cur.x, cur.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buildRoundedOrthogonalPath(poly, 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildRoutePath(points, codes) {
|
||||||
|
if (!Array.isArray(points) || points.length === 0) return '';
|
||||||
|
const poly = [];
|
||||||
|
appendPolylinePoint(poly, points[0].x, points[0].y);
|
||||||
|
for (let i = 1; i < points.length; i++) {
|
||||||
|
const prev = points[i - 1];
|
||||||
|
const cur = points[i];
|
||||||
|
const prevTransfer = isTransferCode(codes?.[i - 1]);
|
||||||
|
const curTransfer = isTransferCode(codes?.[i]);
|
||||||
|
|
||||||
|
if (prev.x === cur.x || prev.y === cur.y) {
|
||||||
|
appendPolylinePoint(poly, cur.x, cur.y);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prevTransfer && curTransfer) {
|
||||||
|
appendPolylinePoint(poly, cur.x, prev.y);
|
||||||
|
} else if (prevTransfer && !curTransfer) {
|
||||||
|
appendPolylinePoint(poly, prev.x, cur.y);
|
||||||
|
} else {
|
||||||
|
appendPolylinePoint(poly, prev.x, cur.y);
|
||||||
|
}
|
||||||
|
appendPolylinePoint(poly, cur.x, cur.y);
|
||||||
|
}
|
||||||
|
return buildRoundedOrthogonalPath(poly, 16);
|
||||||
|
}
|
||||||
|
|
||||||
async function loadMap() {
|
async function loadMap() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/public/fares/map/light');
|
const res = await fetch('/api/public/fares/map/light');
|
||||||
@@ -273,11 +384,7 @@
|
|||||||
y: stationYByCanonical[code] ?? yLine
|
y: stationYByCanonical[code] ?? yLine
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
const d = buildLinePath(pts, yLine);
|
||||||
let d = `M ${pts[0].x} ${pts[0].y}`;
|
|
||||||
for (let i = 1; i < pts.length; i++) {
|
|
||||||
d += ` L ${pts[i].x} ${pts[i].y}`;
|
|
||||||
}
|
|
||||||
svgContent += `<path d="${d}" fill="none" stroke="${li.color}" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" />`;
|
svgContent += `<path d="${d}" fill="none" stroke="${li.color}" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" />`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -496,7 +603,8 @@
|
|||||||
const group = document.createElementNS(ns, 'g');
|
const group = document.createElementNS(ns, 'g');
|
||||||
group.setAttribute('class', 'route-overlay-group');
|
group.setAttribute('class', 'route-overlay-group');
|
||||||
|
|
||||||
const pathData = points.map((pt, idx) => `${idx === 0 ? 'M' : 'L'} ${pt.x} ${pt.y}`).join(' ');
|
const pathData = buildRoutePath(points, currentRoute);
|
||||||
|
if (!pathData) return;
|
||||||
|
|
||||||
const glow = document.createElementNS(ns, 'path');
|
const glow = document.createElementNS(ns, 'path');
|
||||||
glow.setAttribute('d', pathData);
|
glow.setAttribute('d', pathData);
|
||||||
|
|||||||
Reference in New Issue
Block a user