fixed train# specific rules. cleaned up display topline and train display on division map
This commit is contained in:
+20
-43
@@ -277,64 +277,41 @@ export function divisionSvg(nodes: DivisionView[]): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* A TRAIN, DRAWN AS A TRAIN — the same vocabulary the Office Area card uses.
|
||||
* ON THE DIVISION MAP, A TRAIN IS A CHIP — name, which way it points, how many cars.
|
||||
*
|
||||
* The chip was a name and a figure, and the figure was Stages left to cross this card: read
|
||||
* once as the car count, and once the unit was spelled out, read as redundant beside the
|
||||
* position the card already draws. What it never said is the thing worth knowing at a glance —
|
||||
* what the train is carrying, whether those cars are loaded, and which end the engine is on.
|
||||
* It was drawn as a full consist here, matching the Office Area card, and reported as too large
|
||||
* and hard to read: a Mainline cell is 152px and a Running Track cell 78px, against a district
|
||||
* card's 166px, and a four-car train plus its engine has to squeeze into a fifth of that. The
|
||||
* Office card is where the consist is worth drawing, because that is where the switching
|
||||
* decisions are made and where there is room to read it.
|
||||
*
|
||||
* WEST ON THE LEFT here too. `cars` is nose first, so an east-facing train is drawn reversed and
|
||||
* its engine lands at the east end, exactly as on the district card.
|
||||
* So this keeps the two things the Division map is actually for — where a train is and which way
|
||||
* it is going — and leaves the cars to the tooltip and to the district.
|
||||
*/
|
||||
c.trains.forEach((t, k) => {
|
||||
const kindOf = (car: string): string =>
|
||||
/caboose/.test(car) ? 'cab' : /hopper/.test(car) ? 'hop' : /boxcar/.test(car) ? 'box'
|
||||
: /reefer/.test(car) ? 'rfr' : /tank/.test(car) ? 'tnk' : /coach/.test(car) ? 'cch' : '?';
|
||||
const cars = t.cars ?? [];
|
||||
const arrow = t.facing === 'w' ? '◀' : t.facing === 'e' ? '▶' : t.facing === 'n' ? '▲' : '▼';
|
||||
const items: { label: string; kind: string }[] = cars.map((car) => ({
|
||||
label: kindOf(car),
|
||||
kind: /^loaded/.test(car) || /caboose/.test(car) ? 'ld' : 'mt',
|
||||
}));
|
||||
items.splice(Math.max(0, Math.min(items.length, t.engineAt ?? 0)), 0, { label: arrow, kind: 'eng' });
|
||||
const laid = t.facing === 'e' ? [...items].reverse() : items;
|
||||
const arrow = t.facing === 'w' ? '\u25c0' : t.facing === 'e' ? '\u25b6' : t.facing === 'n' ? '\u25b2' : '\u25bc';
|
||||
const loaded = cars.filter((x) => /^loaded/.test(x) || /caboose/.test(x)).length;
|
||||
const label = cars.length === 0 ? `${t.label} ${arrow}` : `${t.label} ${arrow}${cars.length}`;
|
||||
|
||||
const nameW = t.label.length * 6.5 + 6;
|
||||
const w = Math.min(c.w - 8, nameW + laid.length * 13 + 6);
|
||||
/**
|
||||
* NARROW THE CARS RATHER THAN DROP THEM.
|
||||
*
|
||||
* A Running Track cell is 78 wide and a four-car train plus its engine wants more than that.
|
||||
* Squeezing is honest; leaving cars out is not — a chip showing three of five cars is a chip
|
||||
* that lies about the train. Below 11px the three-letter type will not fit, so the blocks
|
||||
* carry the load state alone and the tooltip carries the words.
|
||||
*/
|
||||
const CARW = Math.max(5, Math.min(13, (w - nameW - 6) / Math.max(1, laid.length)));
|
||||
const w = Math.min(c.w - 8, label.length * 6.6 + 12);
|
||||
// A train on a Mainline card sits in ITS region; anywhere else it just sits on the card.
|
||||
const inRegion = c.regions > 1 && typeof t.region === 'number';
|
||||
const slotX = inRegion ? c.x + 6 + RW * (t.region ?? 0) + RW / 2 : c.x + c.w / 2;
|
||||
const spread = inRegion ? 0 : (k - (c.trains.length - 1) / 2) * (w + 4);
|
||||
const tx = slotX + spread;
|
||||
const dir = t.direction === 'west' ? ' ◀ west' : t.direction === 'east' ? ' east ▶' : '';
|
||||
const dir = t.direction === 'west' ? ' \u25c0 west' : t.direction === 'east' ? ' east \u25b6' : '';
|
||||
const stages =
|
||||
typeof t.stagesLeft === 'number'
|
||||
? ` · ${t.stagesLeft} Stage${t.stagesLeft === 1 ? '' : 's'} still to run across this card` +
|
||||
? ` \u00b7 ${t.stagesLeft} Stage${t.stagesLeft === 1 ? '' : 's'} still to run across this card` +
|
||||
' (Stages, not regions: a card is two regions of fixed distance, and how many Stages a' +
|
||||
' train takes over them depends on the card speed and the train)'
|
||||
: '';
|
||||
out += `<g class="bs-train" data-tip="${esc(t.label)} — carrying ${esc(cars.join(', ') || 'no cars')}, nose first${
|
||||
inRegion ? ` · region ${(t.region ?? 0) + 1} of ${c.regions}${dir}` : ''
|
||||
}${esc(stages)}">` +
|
||||
out += `<g class="bs-train" data-tip="${esc(t.label)} \u2014 carrying ${esc(cars.join(', ') || 'no cars')}${
|
||||
cars.length ? ` (${loaded} loaded)` : ''
|
||||
}${inRegion ? ` \u00b7 region ${(t.region ?? 0) + 1} of ${c.regions}${dir}` : ''}${esc(stages)}">` +
|
||||
`<rect x="${tx - w / 2}" y="${c.y + 22}" width="${w}" height="19" rx="3"/>` +
|
||||
`<text class="bs-tlab" x="${tx - w / 2 + 4}" y="${c.y + 35}">${esc(t.label)}</text>`;
|
||||
laid.forEach((it, n) => {
|
||||
const bx = tx - w / 2 + nameW + n * CARW;
|
||||
out += `<rect class="bs-tcar bs-t-${it.kind}" x="${bx}" y="${c.y + 25}" width="${Math.max(3, CARW - 2)}" height="13" rx="2"/>`;
|
||||
if (CARW >= 11) {
|
||||
out += `<text class="bs-tcarlab" x="${bx + (CARW - 2) / 2}" y="${c.y + 35}" text-anchor="middle">${esc(it.label)}</text>`;
|
||||
}
|
||||
});
|
||||
`<text class="bs-tlab" x="${tx}" y="${c.y + 35}" text-anchor="middle">${esc(label)}</text>`;
|
||||
out += '</g>';
|
||||
});
|
||||
out += '</g>';
|
||||
@@ -716,8 +693,8 @@ export function officeSvg(
|
||||
t.facing === 'e' ? 'east' : t.facing === 'w' ? 'west' : t.facing === 'n' ? 'north' : 'south';
|
||||
const consistWords = t.cars.length === 0 ? 'no cars' : t.cars.join(', ');
|
||||
out += `<g class="bs-crew" data-tip="${esc(
|
||||
`${t.label} \u2014 engine pointing ${facingWord}, carrying ${consistWords} (nose first). Drawn as it stands: west is on the left.`,
|
||||
)}"><rect x="${tx}" y="${RAIL - 11}" width="${tw}" height="22" rx="3"/>`;
|
||||
`${t.label} — engine pointing ${facingWord}, carrying ${consistWords}` + (t.what ? `\n\n${t.what}` : ''),
|
||||
)}"><rect x="${tx}" y="${RAIL - 11}" width="${tw}" height="22" rx="3"/>`;
|
||||
out += `<text class="bs-tlab" x="${tx + 4}" y="${RAIL + 4}">${esc(t.label)}</text>`;
|
||||
laid.forEach((it, n) => {
|
||||
const bx = tx + 28 + n * cw;
|
||||
|
||||
Reference in New Issue
Block a user