Compare commits

..

4 Commits

Author SHA1 Message Date
ElementalAlchemist f6f42fbb45 Minor cleanup of the standard mode 10 months 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).
10 months ago
ElementalAlchemist 5410b5c1fe Shorten refresh interval to 2.5 seconds 10 months 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.
10 months 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