Compare commits

..

4 Commits

Author SHA1 Message Date
ElementalAlchemist f6f42fbb45 Minor cleanup of the standard mode 1 week ago
ElementalAlchemist 96a71c3519 Add point progress mode
Adds a new mode that makes the full width be exactly one point, and the bus drives across the canvas.

This also resizes the canvas to the requested size (1580x62).
1 week ago
ElementalAlchemist 5410b5c1fe Shorten refresh interval to 2.5 seconds 1 week ago
ElementalAlchemist 8b7b87d450 Fix bus stops disappearing early
The existing code tried to avoid infinite loops due to floating point math. It turns out the +1 was overzealous and caused bus stop signs to disappear before expected at high scale numbers.
1 week ago

Binary file not shown.

Before

Width:  |  Height:  |  Size: 439 B

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 520 B

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 4.2 KiB

@ -3,7 +3,7 @@
margin-top: 20px;
}
#scale-disclaimer {
.settings-disclaimer {
font-size: 75%;
font-style: italic;
}

@ -7,13 +7,18 @@
<script src="drive.js"></script>
</head>
<body>
<canvas id="road" width="1920" height="100"></canvas>
<canvas id="road" width="1580" height="62"></canvas>
<label id="scale">
Scale:
<input id="scale-input" type="number" value="1" min="0.1" step="0.1" />
</label>
<p id="scale-disclaimer">
Scale modifications will be applied on the next update, which occur every 10 seconds.
<label id="point-progress">
<input id="point-progress-checkbox" type="checkbox" />
Point Progress Mode
</label>
<p class="settings-disclaimer">
Settings modifications will be applied on the next update, which occur every 2.5 seconds.
</p>
<p class="settings-disclaimer">The scale setting is ignored in Point Progress Mode.</p>
</body>
</html>

@ -21,10 +21,8 @@ const COLORS = {
},
};
const KEY_OUT_COLOR = "#2b6ec6";
// The width from the left side of the bus image to the front of the bus
const BUS_FRONT_OFFSET = 73;
const BUS_FRONT_OFFSET = 72;
// Start time of each day phase
const DAY_START_MINUTES = 450;
@ -49,7 +47,12 @@ const POINT_IMAGE = new Image();
POINT_IMAGE.src = "point.png";
// This should match the HTML canvas width
const CANVAS_PIXEL_WIDTH = 1920;
const CANVAS_PIXEL_WIDTH = 1580;
const BUS_TRAVEL_WIDTH = CANVAS_PIXEL_WIDTH - BUS_FRONT_OFFSET;
const PIXELS_PER_MILE = BUS_TRAVEL_WIDTH / 360;
const PIXELS_PER_MINUTE = BUS_TRAVEL_WIDTH / 480;
const FULL_SPEED_MILES_PER_MINUTE = 0.75;
function nextPhase(timeOfDay) {
switch (timeOfDay) {
@ -81,17 +84,12 @@ function drawBackground(context, timeOfDay, leftX, width) {
const groundColor = COLORS[timeOfDay].ground;
const surfaceColor = COLORS[timeOfDay].surface;
context.fillStyle = KEY_OUT_COLOR;
context.fillRect(leftX, 80, width, 20);
context.fillStyle = COLORS[timeOfDay].sky;
context.fillRect(leftX, 0, width, 80);
context.fillRect(leftX, 0, width, 56);
context.fillStyle = COLORS[timeOfDay].surface;
context.fillRect(leftX, 80, width, 1);
context.fillRect(leftX, 56, width, 1);
context.fillStyle = COLORS[timeOfDay].ground;
context.fillRect(leftX, 81, width, 7);
context.fillRect(leftX, 89, width, 3);
context.fillRect(leftX, 94, width, 2);
context.fillRect(leftX, 99, width, 1);
context.fillRect(leftX, 57, width, 5);
}
async function drawRoad() {
@ -108,19 +106,62 @@ async function drawRoad() {
const context = canvas.getContext("2d");
// Clear the previous canvas before starting
context.clearRect(0, 0, CANVAS_PIXEL_WIDTH, 100);
// Background the whole thing as the key-out color in case we need to bail
// out before drawing (e.g. we're in a non-DB game menu)
context.fillStyle = KEY_OUT_COLOR;
context.fillRect(0, 0, CANVAS_PIXEL_WIDTH, 100);
context.clearRect(0, 0, CANVAS_PIXEL_WIDTH, 62);
const pointModeCheckbox = document.getElementById("point-progress-checkbox");
if (pointModeCheckbox.checked) {
drawRoadPoint(context, busData);
} else {
drawRoadDynamic(context, busData);
}
}
function drawRoadPoint(context, busData) {
const busDistance = (busData.odometer + 250.7) % 360;
const busRemainingDistance = 360 - busDistance;
const busRemainingDistancePixels = busRemainingDistance * PIXELS_PER_MILE;
const busDistancePixels = busDistance * PIXELS_PER_MILE;
let x = busDistancePixels + BUS_FRONT_OFFSET;
drawBackground(context, busData.timeofday, 0, x);
let currentTimeOfDay = busData.timeofday;
let currentTime = busData.clock_minutes;
while (x < CANVAS_PIXEL_WIDTH) {
const nextTimeOfDay = nextPhase(currentTimeOfDay);
const nextStartTime = phaseStartTime(nextTimeOfDay);
let thisDuration = nextStartTime - currentTime;
if (thisDuration < 0) {
thisDuration += 1440;
}
const pixelWidth = thisDuration * PIXELS_PER_MINUTE;
drawBackground(context, currentTimeOfDay, x, pixelWidth);
x += pixelWidth;
currentTimeOfDay = nextTimeOfDay;
currentTime += thisDuration;
}
context.drawImage(POINT_IMAGE, CANVAS_PIXEL_WIDTH - POINT_OFFSET, 0);
for (const busStopDistance of BUS_STOP_POSITIONS) {
const busStopPixelPosition =
BUS_FRONT_OFFSET + PIXELS_PER_MILE * busStopDistance - BUS_STOP_OFFSET;
context.drawImage(BUS_STOP_IMAGE, busStopPixelPosition, 16);
}
if (busData.timeofday === "night") {
context.drawImage(BUS_NIGHT_IMAGE, busDistancePixels, 32);
} else {
context.drawImage(BUS_DAY_IMAGE, busDistancePixels, 32);
}
}
const currentTime = busData.clock_minutes;
function drawRoadDynamic(context, busData) {
const distance = busData.odometer;
const timeOfDay = busData.timeofday;
drawBackground(context, timeOfDay, 0, BUS_FRONT_OFFSET);
const maxWidth = CANVAS_PIXEL_WIDTH - BUS_FRONT_OFFSET;
// The default scaling factor (1) is 20 seconds per pixel at max speed.
// This gives us
// - 3px per minute
@ -131,13 +172,11 @@ async function drawRoad() {
}
const startMinute = busData.clock_minutes;
const timeDuration = maxWidth / (3 * scaleFactor);
let previousTime = startMinute;
let previousTimeOfDay = timeOfDay;
let remainingDuration = timeDuration;
let x = BUS_FRONT_OFFSET;
while (remainingDuration > 0) {
while (x < CANVAS_PIXEL_WIDTH) {
const nextTimeOfDay = nextPhase(previousTimeOfDay);
const nextStartTime = phaseStartTime(nextTimeOfDay);
@ -146,11 +185,9 @@ async function drawRoad() {
thisDuration += 1440;
}
// TODO Figure out scaling factor
const pixelWidth = thisDuration * 3 * scaleFactor;
drawBackground(context, previousTimeOfDay, x, pixelWidth);
remainingDuration -= thisDuration;
previousTime = nextStartTime;
previousTimeOfDay = nextTimeOfDay;
x += pixelWidth;
@ -187,7 +224,7 @@ async function drawRoad() {
const distanceTrackedOnRoute = distanceTracked % 360;
let nextBusStopPosition = null;
for (const busStopPosition of BUS_STOP_POSITIONS) {
if (busStopPosition >= distanceTrackedOnRoute + 1) {
if (busStopPosition >= distanceTrackedOnRoute + 0.05) {
nextBusStopPosition = busStopPosition;
break;
}
@ -198,17 +235,17 @@ async function drawRoad() {
const nextBusStopDistance = nextBusStopPosition - distanceTrackedOnRoute;
distanceTracked += nextBusStopDistance;
x += nextBusStopDistance * 4 * scaleFactor;
context.drawImage(BUS_STOP_IMAGE, x - BUS_STOP_OFFSET, 0);
context.drawImage(BUS_STOP_IMAGE, x - BUS_STOP_OFFSET, 16);
}
if (timeOfDay === "night") {
context.drawImage(BUS_NIGHT_IMAGE, 0, 0);
context.drawImage(BUS_NIGHT_IMAGE, 0, 32);
} else {
context.drawImage(BUS_DAY_IMAGE, 0, 0);
context.drawImage(BUS_DAY_IMAGE, 0, 32);
}
}
window.addEventListener("DOMContentLoaded", (event) => {
drawRoad();
setInterval(drawRoad, 10000);
setInterval(drawRoad, 2500);
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 397 B

After

Width:  |  Height:  |  Size: 4.4 KiB

Loading…
Cancel
Save