aframe-hotspots
Version:
A-Frame component for interactive VR hotspots with audio and scene transitions
179 lines (162 loc) • 6.43 kB
JavaScript
export const FaceCameraComponent = {
// ... face-camera component code ...
tick: function () {
const camera = document.querySelector("[camera]").object3D;
this.el.object3D.lookAt(camera.position);
},
};
export const HotspotsComponent = {
// ... hotspots component code ...
init: function () {
this.el.addEventListener("reloadspots", function (evt) {
var currspotgroup = document.getElementById(evt.detail.currspots);
currspotgroup.setAttribute("visible", "false");
var newspotgroup = document.getElementById(evt.detail.newspots);
newspotgroup.setAttribute("visible", "true");
console.log(
"Hotspots reloaded from",
evt.detail.currspots,
"to",
evt.detail.newspots
);
console.log(
"New hotspot group visibility:",
evt.detail.newspots,
newspotgroup.getAttribute("visible")
);
});
},
};
export const SpotComponent = {
// ... spot component code ...
schema: {
linkto: { type: "string", default: "" },
spotgroup: { type: "string", default: "" },
label: { type: "string", default: "" },
audio: { type: "string", default: "" },
labelBackground: { type: "color", default: "#333333" }, // New property
labelPadding: { type: "number", default: 0.2 },
lineHeight: { type: "number", default: 0.4 },
},
init: function () {
this.el.setAttribute("src", "#hotspot");
this.el.setAttribute("look-at", "#cam");
var data = this.data;
var el = this.el;
console.log("Initializing hotspot with label:", data.label);
if (data.label !== "") {
// Create container for label + background
const labelContainer = document.createElement("a-entity");
labelContainer.setAttribute("position", "0 -0.6 0");
// Add background panel
const background = document.createElement("a-plane");
background.setAttribute("color", data.labelBackground);
background.setAttribute("opacity", 0.8);
background.setAttribute(
"width",
data.label.length * 0.15 + data.labelPadding
); // Dynamic width
background.setAttribute("height", 0.3);
background.setAttribute("position", "0 0 -0.01"); // Behind text
// Add text label
const textEl = document.createElement("a-text");
textEl.setAttribute("value", data.label);
textEl.setAttribute("align", "center");
textEl.setAttribute("color", "#FFFFFF"); // White text by default
textEl.setAttribute("position", "0 0 0"); // In front of background
// Assemble components
labelContainer.appendChild(background);
labelContainer.appendChild(textEl);
el.appendChild(labelContainer);
}
if (data.audio !== "") {
var audioEl = document.createElement("a-sound");
audioEl.setAttribute("src", data.audio);
audioEl.setAttribute("autoplay", "false");
audioEl.setAttribute("loop", "true");
audioEl.setAttribute("volume", "1");
el.appendChild(audioEl);
console.log("Audio element added with source:", data.audio);
audioEl.addEventListener("sound-loaded", function () {
console.log("Sound loaded -force stop playing:", data.label);
audioEl.components.sound.stopSound();
button.setAttribute("text", "value: Play; align: center; color: #FFF");
audioReady = true;
});
var button = document.createElement("a-plane");
button.setAttribute("color", "#ff0000");
button.setAttribute("width", "0.5");
button.setAttribute("height", "0.3");
button.setAttribute("position", "0 -1 0");
button.setAttribute("text", "value: Play; align: center; color: #FFF");
el.appendChild(button);
console.log("Play/Pause button added for hotspot:", data.label);
var audioReady = false;
audioEl.addEventListener("sound-loaded", function () {
console.log("Sound loaded for hotspot:", data.label);
audioReady = true;
});
var toggleAudio = function () {
if (audioEl.components.sound.isPlaying) {
audioEl.components.sound.stopSound();
button.setAttribute(
"text",
"value: Play; align: center; color: #FFF"
);
console.log("Audio paused for hotspot:", data.label);
} else {
audioEl.components.sound.playSound();
button.setAttribute(
"text",
"value: Pause; align: center; color: #FFF"
);
console.log("Audio playing for hotspot:", data.label);
}
};
button.addEventListener("click", function (evt) {
evt.stopPropagation();
console.log("Button clicked for hotspot:", data.label);
if (!audioReady) {
console.log("Waiting for audio to load...");
var onLoaded = function () {
audioEl.removeEventListener("sound-loaded", onLoaded);
toggleAudio();
};
audioEl.addEventListener("sound-loaded", onLoaded);
return;
}
toggleAudio();
});
}
el.addEventListener("click", function (evt) {
var audioChild = el.querySelector("a-sound");
if (
audioChild &&
audioChild.components &&
audioChild.components.sound &&
audioChild.components.sound.isPlaying
) {
audioChild.components.sound.stopSound();
var btn = el.querySelector("a-plane");
if (btn) {
btn.setAttribute("text", "value: Play; align: center; color: #FFF");
}
console.log("Audio reset on hotspot:", data.label);
}
var sky = document.getElementById("skybox");
sky.setAttribute("src", data.linkto);
console.log("Skybox changed to:", data.linkto);
var spotcomp = document.getElementById("spots");
var currspots = el.parentElement.getAttribute("id");
spotcomp.emit("reloadspots", {
newspots: data.spotgroup,
currspots: currspots,
});
});
},
};
if (typeof window !== "undefined" && window.AFRAME) {
window.AFRAME.registerComponent("face-camera", FaceCameraComponent);
window.AFRAME.registerComponent("hotspots", HotspotsComponent);
window.AFRAME.registerComponent("spot", SpotComponent);
}