WebController - Utility Methods¶
This section includes all the functions that are useful to the sample, but don’t involve any functions from the Genvid API.
In This Section
popularityToText¶
popularityToText(popularity)
The popularityToText method converts a popularity value to a text value.
// Converts popularity value to popularity text
popularityToText(popularity) {
const hearts = ["💔", "♡", "♥", "💕"];
const levels = [0.1, 1.0, 5.0];
for (let i = 0; i < hearts.length; ++i) {
if (popularity < levels[i]) {
return hearts[i];
}
}
return hearts[levels.length];
}
makeCircleZ¶
makeCircleZ(dst, x, y, z, r, c)
The makeCircleZ method prepares a circle on the XY plane centered at coordinates x,y,z of radius r and color c. All these values are sent as parameters to the method. We use it to determine the correct positions for each WebGL circle.
// Utility routine preparing a circle on the XY-plane
// centered at {x,y,z}, of radius r and color c.
makeCircleZ(dst, x, y, z, r, c) {
dst.push(
// X Y Z U V R G B A
x - r, y - r, z, 0.0, 0.0, c.x, c.y, c.z, c.w,
x + r, y - r, z, 1.0, 0.0, c.x, c.y, c.z, c.w,
x + r, y + r, z, 1.0, 1.0, c.x, c.y, c.z, c.w,
x - r, y + r, z, 0.0, 1.0, c.x, c.y, c.z, c.w
);
}
projectWithRadius¶
projectWithRadius(mat, pos3d, rad3d)
The projectWithRadius method converts a 3D radius around a 3D position using the viewProjection matrix. We use it to determine a hitbox for each circle when trying to click on it.
// Converts a @rad3d around a 3D position @pos3d using the viewProjection matrix @mat.
// Returns an array [pos2d, rad2d].
projectWithRadius(mat, pos3d, rad3d) {
// There might be a more mathematically sound solution to this,
// but I've decided to use the shotgun approach and just project
// 8 positions (add/sub radius to every dimension), and keep
// the one which yields the largest 2D distance.
let pos2d = genvidMath.projectPosition(mat, pos3d);
let radSq2d = 0;
let offsets = [
genvidMath.vec3(rad3d, 0, 0),
genvidMath.vec3(-rad3d, 0, 0),
genvidMath.vec3(0, rad3d, 0),
genvidMath.vec3(0, -rad3d, 0),
genvidMath.vec3(0, 0, rad3d),
genvidMath.vec3(0, 0, -rad3d),
];
for (let i = 0; i < offsets.length; ++i) {
let off = offsets[i];
let nPos3d = genvidMath.add3D(pos3d, off);
let nPos2d = genvidMath.projectPosition(mat, nPos3d);
let nRadSq2d = genvidMath.lengthSq2D(genvidMath.sub2D(pos2d, nPos2d));
radSq2d = Math.max(radSq2d, nRadSq2d);
}
return [pos2d, Math.sqrt(radSq2d)];
}
centerAt¶
centerAt(htmlElement, pos_2d, offsetPixels)
The centerAt method modifies an HTML element position to be centered at the 2D position sent. We use it to move the name div-element displayed above each object.
// Changes the HTML element position to be at the center of the pos 2d sent
centerAt(htmlElement, pos2d, offsetPixels) {
// Converts from [-1, 1] range to [0, 1].
let vh = genvidMath.vec2(0.5, 0.5);
let pos2dN = genvidMath.mad2D(pos2d, vh, vh);
// Converts from [0, 1] range to [0, w].
let p = htmlElement.parentElement;
let pSize = genvidMath.vec2(p.clientWidth, p.clientHeight);
let posInParent = genvidMath.mul2D(pos2dN, pSize);
// Adjusts for centering element.
let eSize = genvidMath.vec2(htmlElement.clientWidth, htmlElement.clientHeight);
let eOffset = genvidMath.muls2D(eSize, -0.5);
let posCentered = genvidMath.add2D(posInParent, eOffset);
// Applies user offset.
const posFinal = genvidMath.sub2D(posCentered, offsetPixels);
Object.assign(htmlElement.style, {
left: posFinal.x + "px",
bottom: posFinal.y + "px",
position: "absolute",
zIndex: "1100"
});
}
preN¶
preN(str, n, c)
The preN method adds empty spaces to a string. We use it to correctly display the data on the Genvid overlay.
// Widens a string to at least n characters, prefixing with spaces.
preN(str, n, c) {
let s = str.length;
if (s < n) {
str = c.repeat(n - s) + str;
}
return str;
}
convertMatrix¶
convertMatrix(rawmat)
The convertMatrix method converts an array of numbers into a Genvid Math 4x4 Matrix. We use it when doing operations that need to use the proper matrix-format, since we recieve the data sent from the game as an array of numbers.
// Converts a 4x4 matrix from 16 labeled scalars into a GenvidMath.mat4 instance.
convertMatrix(rawmat) {
return genvidMath.mat4(
genvidMath.vec4(rawmat[0], rawmat[4], rawmat[8], rawmat[12]),
genvidMath.vec4(rawmat[1], rawmat[5], rawmat[9], rawmat[13]),
genvidMath.vec4(rawmat[2], rawmat[6], rawmat[10], rawmat[14]),
genvidMath.vec4(rawmat[3], rawmat[7], rawmat[11], rawmat[15]));
}
findOrCreateTagDiv¶
findOrCreateTagDiv(cube)
The findOrCreateTagDiv method finds or creates the div that displays the name of the object that moves with the object.
// Finds or creates the div needed to display the name of the cube on the cube
findOrCreateTagDiv(cube) {
let elemId = "cube_tag_" + cube.name;
let elem = document.querySelector("#" + elemId);
if (elem == null) {
elem = document.createElement("div");
elem.id = elemId;
elem.textContent = cube.name;
elem.classList.add("tag");
let parent = document.querySelector("#video_overlay");
parent.appendChild(elem);
elem.addEventListener("click", () => this.onSelect(elem.textContent), false);
this.cubeTagElements.push(elem);
}
elem.style.display = "block";
return elem;
}
msToDuration¶
msToDuration(duration)
The msToDuration method converts milliseconds into days, hours, minutes, and seconds.
// Method used to convert ms to specific duration
msToDuration(duration) {
const msInADay = 1000 * 60 * 60 * 24;
const date = new Date(duration);
const days = (duration - (duration % msInADay)) / msInADay;
return `${days ? `${days}:` : ""}${date.toLocaleTimeString(undefined, {hour12: false, timeZone: "GMT"})}:${this.preN(date.getMilliseconds().toFixed(0), 3, "0")}`;
}
checkFullScreen¶
checkFullScreen()
The checkFullScreen method returns the current fullscreen status.
checkFullScreen() {
return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;
}