Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into HelpPage
Browse files Browse the repository at this point in the history
  • Loading branch information
jonha1 committed Apr 9, 2024
2 parents 05e5c98 + 09712d5 commit d69b33f
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 69 deletions.
107 changes: 93 additions & 14 deletions app/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,70 @@ nav h1 {
color: white;
}

nav button, nav input, nav select, button {
background-color: #e74c3c;
/* beacon-button is the class name for the buttons that appear from the callouts beacon */

.nav-button,
.beacon-button,
nav input,
nav select {
background-color: #e74c3d;
color: #fff;
border: none;
padding: 15px;
border-radius: 8px;
cursor: pointer;
font-size: 1.2em; /* Larger font size for buttons, inputs, and select */
margin-right: 10px; /* Add some spacing between controls */
font-size: 1.2em;
/* Larger font size for buttons, inputs, and select */
margin-right: 10px;
/* Add some spacing between controls */
max-width: 20%;
}


#rate {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
/* border: dashed red; */
background-color: #e74c3d;
cursor: pointer;
font-size: 1.1em;
margin-right: 10px;
padding: 2%;
border-radius: 8px;
max-width: 20%;
}

#rate div{
height: 3vh;
padding: 0vw 1.5vw;
font-size: 1.1em;
color: white;
/* text-align: center; */
display: flex;
justify-content: center;
align-items: center;
}

#rate button {
/* margin: 0px 6px; */
/* Green */
background-color: transparent;
border: none;
color: white;
/* text-align: center; */
padding: 2vw;
font-size: 1em;
display: flex;
justify-content: center;
align-items: center;
}

#rate button:hover {
cursor: pointer;
}

/* Speaking and playback rate selectors don't need to be as large */
nav input[type="number"] {
max-width: 10%;
Expand All @@ -51,7 +103,8 @@ nav select {
}

/* GPX file selector and seek position should be wider -- probably not running on a phone */
nav input[type="file"], nav input[type="range"] {
nav input[type="file"],
nav input[type="range"] {
max-width: none;
}

Expand All @@ -76,13 +129,16 @@ main {

#map {
width: 100%;
height: 300px; /* Adjusted height for better visibility */
border: 2px solid #000; /* Higher contrast for the map border */
height: 300px;
/* Adjusted height for better visibility */
border: 2px solid #000;
/* Higher contrast for the map border */
margin-bottom: 15px;
}

#recentCalloutsArea {
height: calc(100vh - 435px); /* all vertical space after map + button row */
height: calc(100vh - 435px);
/* all vertical space after map + button row */
overflow-y: auto;
flex-basis: 100%;
}
Expand All @@ -92,9 +148,11 @@ main {
margin: 0;
}

#recentCalloutsList li, #recentCalloutsArea p {
#recentCalloutsList li,
#recentCalloutsArea p {
list-style: none;
border-bottom: 2px solid #000; /* Higher contrast for list item borders */
border-bottom: 2px solid #000;
/* Higher contrast for list item borders */
padding: 15px;
margin: 0;
overflow: hidden;
Expand All @@ -120,14 +178,34 @@ main {
/* display map + recent callouts side-by-side on sufficiently wide screens */
@media screen and (min-width: 600px) {
#map {
height: calc(100vh - 140px); /* all vertical space after button row */
height: calc(100vh - 140px);
/* all vertical space after button row */
width: 48%;
}

#recentCalloutsArea {
height: calc(100vh - 140px); /* all vertical space after button row */
height: calc(100vh - 140px);
/* all vertical space after button row */
flex-basis: 48%;
}

#rate {
font-size: 1.2em;
padding: 0px;
}

#rate div{
font-size: 1.2em;
}

#rate button {
padding: 15px;
font-size: 1.2em;
}

#rate button:hover {
cursor: pointer;
}
}

/* Current position marker on map */
Expand All @@ -136,7 +214,8 @@ main {
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 40px solid red; /* You can change the color */
border-bottom: 40px solid red;
/* You can change the color */
transform-origin: bottom center;
}

Expand All @@ -161,4 +240,4 @@ img {
.row {
margin-bottom: 20px;
} */
} */
74 changes: 42 additions & 32 deletions app/js/audio/notabeacon.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function createBeacon(latitude, longitude, locationProvider, audioQueue)
const onCourse = new Audio( 'app/sounds/beacons/Classic/Classic_OnAxis.wav');
const offCourse = new Audio('app/sounds/beacons/Classic/Classic_OffAxis.wav');
onCourse.loop = true;
onCourse.muted = true;
onCourse.volume = 0;
offCourse.loop = true;

const onCourseSource = audioContext.createMediaElementSource(onCourse);
Expand All @@ -34,46 +34,56 @@ export function createBeacon(latitude, longitude, locationProvider, audioQueue)
onCourse.play();
offCourse.play();
},

stop: () => {
onCourse.pause();
offCourse.pause();
},
recomputePosition: () => {
relativePosition = locationProvider.normalizedRelativePosition(sourceLocation);
panner.setPosition(relativePosition.x, relativePosition.y, 0);

iEnabled: () => (!onCourse.paused || !offCourse.paused),

announceDistance: (distanceMeters) => {
// Only announce if not actively playing something else (distance would be stale if queued)
if (!audioQueue.isPlaying) {
lastAnnouncedDistance = distanceMeters;
audioQueue.addToQueue({ soundUrl: 'app/sounds/sense_mobility.wav' })
audioQueue.addToQueue({ text: `Beacon: ${distanceMeters.toFixed(0)} meters` })
}
},
};

// Reevaluate beacon state at most once per audio loop
// "ended" event is not triggered by looped audio, so approximate restart based on time
onCourse.addEventListener('timeupdate', () => {
if (onCourse.currentTime < 0.1) {
const distanceMeters = locationProvider.distance(sourceLocation, { units: "meters" });
if (distanceMeters < foundProximityMeters) {
// Beacon found -- stop the audio
beacon.stop();
new Audio('app/sounds/SS_beaconFound2_48k.wav').play();
} else if (Math.abs(lastAnnouncedDistance - distanceMeters) > announceEveryMetters) {
// We're closer/further by some threshold -- announce distance
// Only announce if not actively playing something else (distance would be stale if queued)
if (!audioQueue.isPlaying) {
lastAnnouncedDistance = distanceMeters;
audioQueue.addToQueue({ soundUrl: 'app/sounds/sense_mobility.wav' })
audioQueue.addToQueue({ text: `Beacon: ${distanceMeters.toFixed(0)} meters` })
}
setOnOffCourse: (relativePosition) => {
// Transition between "on" and "off" beacons
const angle = Math.atan2(relativePosition.x, relativePosition.y) * 180 / Math.PI;
if (Math.abs(angle) < onCourseAngle) {
onCourse.volume = 1.0;
offCourse.volume = 0;
} else {
// Transition between "on" and "off" beacons
const angle = Math.atan2(relativePosition.x, relativePosition.y) * 180 / Math.PI;
if (Math.abs(angle) < onCourseAngle) {
onCourse.muted = false;
offCourse.muted = true;
} else {
onCourse.muted = true;
offCourse.muted = false;
onCourse.volume = 0;
offCourse.volume = 1.0;
}
},

recomputePosition: () => {
// Reevaluate how on-course we are
if (beacon.iEnabled()) {
relativePosition = locationProvider.normalizedRelativePosition(sourceLocation);
panner.setPosition(relativePosition.x, relativePosition.y, 0);

const distanceMeters = locationProvider.distance(sourceLocation, { units: "meters" });
if (distanceMeters < foundProximityMeters) {
// Beacon found -- stop the audio
beacon.stop();
new Audio('app/sounds/SS_beaconFound2_48k.wav').play();
} else if (Math.abs(lastAnnouncedDistance - distanceMeters) > announceEveryMetters) {
// We're closer/further by some threshold -- announce distance
beacon.announceDistance(distanceMeters);
} else if (onCourse.currentTime < 0.1) {
// Update the beacon sound, if just looped
beacon.setOnOffCourse(relativePosition);
}
}
}
});
},
};

// Hook up listeners
locationProvider.events.addEventListener('locationUpdated', beacon.recomputePosition)
Expand Down
16 changes: 14 additions & 2 deletions app/js/audio/sound.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,25 @@ export function createSpatialPlayer(locationProvider) {
// Speech synthesis customization
voices: null,
voice: null,
rate: null,
rate: 2,
setVoice(voiceIndex) {
player.voice = player.voices[voiceIndex];
},
setRate(rate) {
player.rate = rate;
},
increaseRate() {
if (player.rate < 5) {
player.rate++;
}
return player.rate;
},
decreaseRate() {
if (player.rate > 1) {
player.rate--;
}
return player.rate;
},

addToQueue(item) {
player.queue.push(item);
Expand Down Expand Up @@ -165,4 +177,4 @@ export function createSpatialPlayer(locationProvider) {
}

return player;
}
}
22 changes: 20 additions & 2 deletions app/js/replay.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import replayGPX from './spatial/gpx.js';
import createMap from './visual/map.js'
import createRecentCalloutList from './visual/recentlist.js';

const maxSpeedupFactor = 9; // max multiple for faster GPX replays

// Actions to take when page is rendered in full
document.addEventListener('DOMContentLoaded', function () {
const locationProvider = createLocationProvider();
Expand Down Expand Up @@ -40,6 +42,10 @@ document.addEventListener('DOMContentLoaded', function () {
const inputElement = document.getElementById("gpxFileInput");
const playPauseButton = document.getElementById("playPauseButton");
const pointSlider = document.getElementById("pointSlider");
const decreaseSpeed = document.getElementById('decreaseSpeed');
const increaseSpeed = document.getElementById('increaseSpeed');
const speedDisplay = document.getElementById('speedupFactor');
let speedupFactor = parseFloat(speedDisplay.textContent);
let playing = false;

inputElement.addEventListener("change", function (event) {
Expand Down Expand Up @@ -78,11 +84,23 @@ document.addEventListener('DOMContentLoaded', function () {
}
});

decreaseSpeed.addEventListener("click", function (e) {
if (speedupFactor > 1) {
speedDisplay.textContent = --speedupFactor;
}
});

increaseSpeed.addEventListener("click", function (e) {
if (speedupFactor < maxSpeedupFactor) {
speedDisplay.textContent = ++speedupFactor;
}
});

playPauseButton.addEventListener("click", function () {
if (gpxPlayer) {
// Read speed setting, and speed up speech proportionally
gpxPlayer.speedUpFactor = document.getElementById("speed").value;
audioQueue.setRate(gpxPlayer.speedUpFactor);
gpxPlayer.speedupFactor = speedupFactor;
audioQueue.setRate(speedupFactor);

// Toggle play/pause
if (!playing) {
Expand Down
4 changes: 2 additions & 2 deletions app/js/spatial/gpx.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function replayGPX(file, map, callbacks) {
const headingCalculator = new HeadingCalculator(headingWindowSize);

let gpxPlayer = {
speedUpFactor: 1,
speedupFactor: 1,
trackPoints: [],

getPointAtIndex: function(index) {
Expand Down Expand Up @@ -60,7 +60,7 @@ function replayGPX(file, map, callbacks) {
this.pause(); // Stop playing when all points are processed
finishedCallback();
}
}, 1000 / this.speedUpFactor // Delay between points in milliseconds
}, 1000 / this.speedupFactor // Delay between points in milliseconds
);
},

Expand Down
1 change: 1 addition & 0 deletions app/js/visual/recentlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ function createRecentCalloutList(locationProvider, audioQueue) {
const beaconLink = document.createElement('button');
beaconLink.innerHTML = '🔊';
beaconLink.title = 'Start beacon';
beaconLink.classList.add('beacon-button');
newCallout.insertBefore(beaconLink, newCallout.firstChild);

beaconLink.addEventListener('click', () => {
Expand Down
Loading

0 comments on commit d69b33f

Please sign in to comment.