Fix catenary layer toggles, tooltip collision, side rail rendering, and typed interruption signs
Deploy & Release / build-and-deploy (push) Failing after 14s
Deploy & Release / build-and-deploy (push) Failing after 14s
This commit is contained in:
5 files changed
+202
-91
No files matched your search
@@ -639,8 +639,8 @@ function drawCatenaryLayer(ctx, trackWidth) {
|
||||
const pixelRatio = MapData.view.pixelRatio;
|
||||
const scale = MapData.view.scale;
|
||||
|
||||
// 1. Contact Wires
|
||||
if(MapData.layers.catenaryWires && MapData.catenaryPolylines){
|
||||
// 1. Contact Wires & Neutral Lines (decoupled toggles)
|
||||
if(MapData.catenaryPolylines && (MapData.layers.catenaryWires || MapData.layers.catenaryNeutrals)){
|
||||
let minX = MapData.view.unconvertX(0) - Config.viewCullMargin / scale;
|
||||
let maxX = MapData.view.unconvertX(mapCanvas.width) + Config.viewCullMargin / scale;
|
||||
let minZ = MapData.view.unconvertY(mapCanvas.height) - Config.viewCullMargin / scale;
|
||||
@@ -650,6 +650,12 @@ function drawCatenaryLayer(ctx, trackWidth) {
|
||||
ctx.lineJoin = 'round';
|
||||
|
||||
for(const poly of MapData.catenaryPolylines){
|
||||
if(poly.is_neutral){
|
||||
if(!MapData.layers.catenaryNeutrals) continue;
|
||||
} else {
|
||||
if(!MapData.layers.catenaryWires) continue;
|
||||
}
|
||||
|
||||
let b = poly.bounds;
|
||||
if(b[2] < minX || b[0] > maxX || b[3] < minZ || b[1] > maxZ) continue;
|
||||
|
||||
@@ -663,7 +669,7 @@ function drawCatenaryLayer(ctx, trackWidth) {
|
||||
}
|
||||
|
||||
if(poly.is_neutral){
|
||||
let w = Math.max(3.5 * pixelRatio, trackWidth * 0.7);
|
||||
let w = Math.max(3.8 * pixelRatio, trackWidth * 0.75);
|
||||
ctx.lineWidth = w;
|
||||
ctx.setLineDash([]);
|
||||
ctx.strokeStyle = '#ffffff';
|
||||
@@ -674,20 +680,23 @@ function drawCatenaryLayer(ctx, trackWidth) {
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
} else if(poly.category === 'side_rail'){
|
||||
ctx.lineWidth = Math.max(2.5 * pixelRatio, trackWidth * 0.45);
|
||||
ctx.setLineDash([8 * pixelRatio, 4 * pixelRatio]);
|
||||
ctx.lineWidth = Math.max(3.0 * pixelRatio, trackWidth * 0.55);
|
||||
ctx.setLineDash([10 * pixelRatio, 5 * pixelRatio]);
|
||||
ctx.strokeStyle = '#111111';
|
||||
ctx.stroke();
|
||||
ctx.lineWidth = Math.max(1.8 * pixelRatio, trackWidth * 0.35);
|
||||
ctx.strokeStyle = poly.color;
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
} else if(poly.category === 'quad'){
|
||||
ctx.lineWidth = Math.max(4 * pixelRatio, trackWidth * 0.85);
|
||||
ctx.lineWidth = Math.max(4.2 * pixelRatio, trackWidth * 0.85);
|
||||
ctx.strokeStyle = '#111111';
|
||||
ctx.stroke();
|
||||
ctx.lineWidth = Math.max(2.2 * pixelRatio, trackWidth * 0.55);
|
||||
ctx.lineWidth = Math.max(2.4 * pixelRatio, trackWidth * 0.55);
|
||||
ctx.strokeStyle = poly.color;
|
||||
ctx.stroke();
|
||||
} else if(poly.category === 'dual'){
|
||||
ctx.lineWidth = Math.max(3.2 * pixelRatio, trackWidth * 0.7);
|
||||
ctx.lineWidth = Math.max(3.4 * pixelRatio, trackWidth * 0.7);
|
||||
ctx.strokeStyle = poly.color;
|
||||
ctx.stroke();
|
||||
} else if(poly.category === 'trolley'){
|
||||
@@ -702,64 +711,117 @@ function drawCatenaryLayer(ctx, trackWidth) {
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Neutral Section Markers
|
||||
// 2. Neutral Section Markers & Detail Signs
|
||||
if(MapData.layers.catenaryNeutrals && MapData.catenaryNeutrals){
|
||||
for(const n of MapData.catenaryNeutrals){
|
||||
let nx = MapData.view.convertX(n.center.x);
|
||||
let ny = MapData.view.convertY(n.center.z);
|
||||
if(nx < -50 || nx > mapCanvas.width + 50 || ny < -50 || ny > mapCanvas.height + 50) continue;
|
||||
if(nx >= -50 && nx <= mapCanvas.width + 50 && ny >= -50 && ny <= mapCanvas.height + 50){
|
||||
let badgeSize = 13 * pixelRatio;
|
||||
ctx.beginPath();
|
||||
ctx.arc(nx, ny, badgeSize, 0, Math.PI * 2);
|
||||
ctx.fillStyle = '#e63946';
|
||||
ctx.fill();
|
||||
ctx.lineWidth = 2 * pixelRatio;
|
||||
ctx.strokeStyle = '#ffffff';
|
||||
ctx.stroke();
|
||||
|
||||
let badgeSize = 13 * pixelRatio;
|
||||
ctx.beginPath();
|
||||
ctx.arc(nx, ny, badgeSize, 0, Math.PI * 2);
|
||||
ctx.fillStyle = '#e63946';
|
||||
ctx.fill();
|
||||
ctx.lineWidth = 2 * pixelRatio;
|
||||
ctx.strokeStyle = '#ffffff';
|
||||
ctx.stroke();
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.font = `bold ${10 * pixelRatio}px "Noto Sans"`;
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText('0V', nx, ny);
|
||||
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.font = `bold ${10 * pixelRatio}px "Noto Sans"`;
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText('0V', nx, ny);
|
||||
if(scale >= 0.035){
|
||||
ctx.font = `bold ${11 * pixelRatio}px "Noto Sans"`;
|
||||
ctx.strokeStyle = '#000000';
|
||||
ctx.lineWidth = 2.5 * pixelRatio;
|
||||
ctx.strokeText(`⛔ ${n.id}`, nx, ny + 18 * pixelRatio);
|
||||
ctx.fillStyle = '#ffcccc';
|
||||
ctx.fillText(`⛔ ${n.id}`, nx, ny + 18 * pixelRatio);
|
||||
}
|
||||
}
|
||||
|
||||
if(scale >= 0.04){
|
||||
ctx.font = `bold ${11 * pixelRatio}px "Noto Sans"`;
|
||||
ctx.strokeStyle = '#000000';
|
||||
ctx.lineWidth = 2.5 * pixelRatio;
|
||||
ctx.strokeText(`⛔ ${n.id}`, nx, ny + 18 * pixelRatio);
|
||||
ctx.fillStyle = '#ffcccc';
|
||||
ctx.fillText(`⛔ ${n.id}`, nx, ny + 18 * pixelRatio);
|
||||
// High zoom boundary signs (NeutralWarning, NeutralBegin, NeutralEnd)
|
||||
if(scale >= 0.04 && n.signs){
|
||||
for(const sign of n.signs){
|
||||
let sx = MapData.view.convertX(sign.x);
|
||||
let sy = MapData.view.convertY(sign.z);
|
||||
if(sx < -20 || sx > mapCanvas.width + 20 || sy < -20 || sy > mapCanvas.height + 20) continue;
|
||||
|
||||
let isWarn = sign.type.includes('Warning');
|
||||
let isBegin = sign.type.includes('Begin');
|
||||
let signColor = isWarn ? '#f59e0b' : (isBegin ? '#e63946' : '#10b981');
|
||||
let signSymbol = isWarn ? '⚠' : (isBegin ? '⛔' : '✓');
|
||||
|
||||
let r = 8 * pixelRatio;
|
||||
ctx.beginPath();
|
||||
ctx.arc(sx, sy, r, 0, Math.PI * 2);
|
||||
ctx.fillStyle = signColor;
|
||||
ctx.fill();
|
||||
ctx.lineWidth = 1.2 * pixelRatio;
|
||||
ctx.strokeStyle = '#ffffff';
|
||||
ctx.stroke();
|
||||
|
||||
ctx.fillStyle = isWarn ? '#000000' : '#ffffff';
|
||||
ctx.font = `bold ${8 * pixelRatio}px "Noto Sans"`;
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText(signSymbol, sx, sy);
|
||||
|
||||
if(scale >= 0.08){
|
||||
ctx.font = `${9 * pixelRatio}px "Noto Sans"`;
|
||||
ctx.strokeStyle = '#000000';
|
||||
ctx.lineWidth = 2 * pixelRatio;
|
||||
ctx.strokeText(sign.type, sx, sy - 12 * pixelRatio);
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.fillText(sign.type, sx, sy - 12 * pixelRatio);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Interruption Markers
|
||||
if(MapData.layers.catenaryInterruptions && MapData.catenaryInterruptions){
|
||||
if(MapData.layers.catenaryInterruptions && MapData.catenaryInterruptions && scale >= 0.015){
|
||||
for(const inter of MapData.catenaryInterruptions){
|
||||
let ix = MapData.view.convertX(inter.center.x);
|
||||
let iy = MapData.view.convertY(inter.center.z);
|
||||
if(ix < -50 || ix > mapCanvas.width + 50 || iy < -50 || iy > mapCanvas.height + 50) continue;
|
||||
|
||||
let s = 10 * pixelRatio;
|
||||
let kind = inter.kind || 'drop';
|
||||
let fillColor = kind === 'warning' ? '#f59e0b' : (kind === 'raise' ? '#10b981' : '#f97316');
|
||||
let textColor = kind === 'warning' ? '#000000' : '#ffffff';
|
||||
let icon = kind === 'warning' ? '⚠' : (kind === 'raise' ? '⤒' : '⤓');
|
||||
|
||||
let s = Math.max(7 * pixelRatio, Math.min(11 * pixelRatio, 220 * scale * pixelRatio));
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(ix, iy - s);
|
||||
ctx.lineTo(ix + s, iy);
|
||||
ctx.lineTo(ix, iy + s);
|
||||
ctx.lineTo(ix - s, iy);
|
||||
ctx.closePath();
|
||||
ctx.fillStyle = '#ff9f1c';
|
||||
ctx.fillStyle = fillColor;
|
||||
ctx.fill();
|
||||
ctx.lineWidth = 1.5 * pixelRatio;
|
||||
ctx.strokeStyle = '#000000';
|
||||
ctx.stroke();
|
||||
|
||||
ctx.fillStyle = '#000000';
|
||||
ctx.font = `bold ${11 * pixelRatio}px "Noto Sans"`;
|
||||
ctx.fillStyle = textColor;
|
||||
ctx.font = `bold ${Math.round(s * 1.05)}px "Noto Sans"`;
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText('⤓', ix, iy);
|
||||
ctx.fillText(icon, ix, iy);
|
||||
|
||||
if(scale >= 0.045){
|
||||
let desc = kind === 'warning' ? '⚠ Разрыв КС' : (kind === 'raise' ? '⤒ Подъем пантографа' : '⤓ Опустить пантограф');
|
||||
ctx.font = `bold ${10 * pixelRatio}px "Noto Sans"`;
|
||||
ctx.strokeStyle = '#000000';
|
||||
ctx.lineWidth = 2.5 * pixelRatio;
|
||||
ctx.strokeText(desc, ix, iy + s + 7 * pixelRatio);
|
||||
ctx.fillStyle = fillColor;
|
||||
ctx.fillText(desc, ix, iy + s + 7 * pixelRatio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -792,7 +854,7 @@ function drawCatenaryLayer(ctx, trackWidth) {
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText('⚡', sx, sy - 1 * pixelRatio);
|
||||
|
||||
if(scale >= 0.03){
|
||||
if(scale >= 0.025){
|
||||
let labelText = `${sub.id} (${sub.nominal_voltage}V)`;
|
||||
ctx.font = `bold ${11 * pixelRatio}px "Noto Sans"`;
|
||||
ctx.textAlign = 'center';
|
||||
|
||||
Reference in new issue
Block a user