Wplace-BlueMarble/docs/utils.js.html
2026-03-17 01:31:43 +00:00

546 lines
41 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>utils.js - Documentation</title>
<script src="scripts/prettify/prettify.js"></script>
<script src="scripts/prettify/lang-css.js"></script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger" class="navicon-button x">
<div class="navicon"></div>
</label>
<label for="nav-trigger" class="overlay"></label>
<nav>
<li class="nav-link nav-home-link"><a href="index.html">Home</a></li><li class="nav-heading">Classes</li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="ApiManager.html">ApiManager</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="ConfettiManager.html">ConfettiManager</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="Observers.html">Observers</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="Overlay.html">Overlay</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="SettingsManager.html">SettingsManager</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="Template.html">Template</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="TemplateManager.html">TemplateManager</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="WindowCredits.html">WindowCredits</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="WindowFilter.html">WindowFilter</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="WindowMain.html">WindowMain</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="WindowSettings.html">WindowSettings</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="WindowTelemetry.html">WindowTelemetry</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="WindowWizard.html">WindowWizard</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="module.exports_module.exports.html">exports</a></span></li><li class="nav-heading"><a href="global.html">Globals</a></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addBr">addBr</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addButton">addButton</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addButtonHelp">addButtonHelp</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addCaption">addCaption</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addCheckbox">addCheckbox</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addDetails">addDetails</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addDiv">addDiv</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addDragbar">addDragbar</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addFieldset">addFieldset</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addForm">addForm</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addHeader">addHeader</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addHr">addHr</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addImg">addImg</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addInput">addInput</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addInputFile">addInputFile</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addLegend">addLegend</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addLi">addLi</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addMenu">addMenu</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addOl">addOl</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addOption">addOption</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addP">addP</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addSelect">addSelect</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addSmall">addSmall</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addSpan">addSpan</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addSummary">addSummary</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addTable">addTable</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addTbody">addTbody</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addTd">addTd</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addTextarea">addTextarea</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addTfoot">addTfoot</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addTh">addTh</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addThead">addThead</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addTimer">addTimer</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addTr">addTr</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#addUl">addUl</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#base64ToUint8">base64ToUint8</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#buildElement">buildElement</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#buildHighlight">buildHighlight</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#buildOverlay">buildOverlay</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#buildTemplate">buildTemplate</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#buildWindow">buildWindow</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#buildWindowed">buildWindowed</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#calculateCanvasTransparency">calculateCanvasTransparency</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#calculateCoordsFromChunked">calculateCoordsFromChunked</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#calculateRelativeLuminance">calculateRelativeLuminance</a></span></li><li class="nav-item"><span class="nav-item-type type-member">M</span><span class="nav-item-name"><a href="global.html#colorpalette">colorpalette</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#colorpaletteForBlueMarble">colorpaletteForBlueMarble</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#consoleError">consoleError</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#consoleLog">consoleLog</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#consoleWarn">consoleWarn</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#convertTemplateToBlob">convertTemplateToBlob</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#createConfetti">createConfetti</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#createJSON">createJSON</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#createObserverBody">createObserverBody</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#createTemplate">createTemplate</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#createTemplateTiles">createTemplateTiles</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#deleteTemplate">deleteTemplate</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#disableTemplate">disableTemplate</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#downloadAllTemplates">downloadAllTemplates</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#downloadAllTemplatesFromStorage">downloadAllTemplatesFromStorage</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#downloadTemplate">downloadTemplate</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#drawTemplateOnTile">drawTemplateOnTile</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#encodedToNumber">encodedToNumber</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#escapeHTML">escapeHTML</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#getClipboardData">getClipboardData</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#getObserverBody">getObserverBody</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#getWplaceVersion">getWplaceVersion</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#handleDisplayError">handleDisplayError</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#handleDisplayStatus">handleDisplayStatus</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#handleDrag">handleDrag</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#handleMinimization">handleMinimization</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#hexToRGB">hexToRGB</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#importJSON">importJSON</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#inject">inject</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#localizeDate">localizeDate</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#localizeDuration">localizeDuration</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#localizeNumber">localizeNumber</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#localizePercent">localizePercent</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#negativeSafeModulo">negativeSafeModulo</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#numberToEncoded">numberToEncoded</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#observe">observe</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#observeBlack">observeBlack</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#rgbToHex">rgbToHex</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#selectAllCoordinateInputs">selectAllCoordinateInputs</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#serverTPtoDisplayTP">serverTPtoDisplayTP</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#setApiManager">setApiManager</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#setSettingsManager">setSettingsManager</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#setTemplatesShouldBeDrawn">setTemplatesShouldBeDrawn</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#setWindowMain">setWindowMain</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#sleep">sleep</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#spontaneousResponseListener">spontaneousResponseListener</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#toggleFlag">toggleFlag</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#uint8ToBase64">uint8ToBase64</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#updateColorList">updateColorList</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#updateInnerHTML">updateInnerHTML</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#updateUserStorage">updateUserStorage</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#viewCanvasInNewTab">viewCanvasInNewTab</a></span></li>
</nav>
<div id="main">
<h1 class="page-title">utils.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>
/** Returns a Date of when Wplace was last updated.
* This is obtained from a certain DOM element which contains the version of Wplace.
* @since 0.90.25
* @returns {Date | undefined} - The date that Wplace was last updated, as a Date.
*/
export function getWplaceVersion() {
const wplaceVersionElement = [...document.querySelectorAll(`body > div > .hidden`)].filter(match => /version:/i.test(match.textContent));
if (wplaceVersionElement[0]) { // If there is at least one match...
const wplaceUpdateTime = wplaceVersionElement[0].textContent?.match(/\d+/); // Obtain the last update time, which is Unix Epoch in milliseconds
return wplaceUpdateTime ? new Date(Number(wplaceUpdateTime[0])) : undefined; // Return the time as a Date, or undefined
}
return undefined;
}
/** Halts execution of this specific userscript, for the specified time.
* This will not block the thread.
* @param {number} time - Time to wait in milliseconds
* @since 0.88.483
* @returns {Promise} Promise of a setTimeout()
*/
export function sleep(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
/** View the canvas in a new tab.
* @param {HTMLCanvasElement | OffscreenCanvas} canvas - The canvas to view
* @param {number} [lifeDuration=60_000] - (Optional) The lifetime of the URL blob in milliseconds
* @since 0.88.484
*/
export async function viewCanvasInNewTab(canvas, lifeDuration = 60_000) {
const final = await canvas.convertToBlob({ type: 'image/png' });
const url = URL.createObjectURL(final); // Creates a blob URL
window.open(url, '_blank'); // Opens a new tab with blob
setTimeout(() => URL.revokeObjectURL(url), lifeDuration); // Destroys the blob after this time (default of 1 minute)
}
/** Returns the localized number format.
* @param {number} number - The number to localize
* @since 0.88.472
* @returns {string} Localized number as a string
*/
export function localizeNumber(number) {
const numberFormat = new Intl.NumberFormat();
return numberFormat.format(number);
}
/** Returns the localized percentage format.
* @param {number} percent - The percentage to localize
* @since 0.88.472
* @returns {string} Localized percentage as a string
*/
export function localizePercent(percent) {
const percentFormat = new Intl.NumberFormat(undefined, {
style: 'percent',
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
return percentFormat.format(percent);
}
/** Returns the localized date format.
* @param {number} date - The date to localize
* @since 0.88.472
* @returns {string} Localized date as a string
*/
export function localizeDate(date) {
const options = {
month: 'long', // July
day: 'numeric', // 23
hour: '2-digit', // 17
minute: '2-digit', // 47
second: '2-digit' // 00
};
return date.toLocaleString(undefined, options);
}
/** Returns the localized duration format.
* @param {number} durationTotalMs - The duration to localize, in milliseconds
* @since 0.88.472
* @returns {string} Localized duration as a string
*/
export function localizeDuration(durationTotalMs) {
// "Total" indicates it is the total time for that unit. E.g. 62 minutes is "62" minutes.
const durationTotalSec = Math.floor(durationTotalMs / 1000);
const durationTotalHr = Math.floor(durationTotalSec / 3600);
// "Only" indicates it is formatted in that unit. E.g. 62 minutes is "2" minutes.
const durationOnlySec = Math.floor(durationTotalSec % 60);
const durationOnlyMin = Math.floor((durationTotalSec % 3600) / 60);
// Duration Object for localization
const duration = {
hours: durationTotalHr,
minutes: durationOnlyMin,
seconds: durationOnlySec
};
// Options Object for localization
const options = {
style: 'short'
};
return new Intl.DurationFormat(undefined, options).format(duration);
}
/** Sanitizes HTML to display as plain-text.
* This prevents some Cross Site Scripting (XSS).
* This is handy when you are displaying user-made data, and you *must* use innerHTML.
* @param {string} text - The text to sanitize
* @returns {string} HTML escaped string
* @since 0.44.2
* @example
* const paragraph = document.createElement('p');
* paragraph.innerHTML = escapeHTML('&lt;u>Foobar.&lt;/u>');
* // Output:
* // (Does not include the paragraph element)
* // (Output is not HTML formatted)
* &lt;p>
* "&lt;u>Foobar.&lt;/u>"
* &lt;/p>
*/
export function escapeHTML(text) {
const div = document.createElement('div'); // Creates a div
div.textContent = text; // Puts the text in a PLAIN-TEXT property
return div.innerHTML; // Returns the HTML property of the div
}
/** Converts the server tile-pixel coordinate system to the displayed tile-pixel coordinate system.
* @param {Array&lt;string, string>} tile - The tile to convert
* @param {Array&lt;string, string>} pixel - The pixel to convert
* @returns {Array&lt;number, number>} Tile and pixel coordinate pair
* @since 0.42.4
* @example
* console.log(serverTPtoDisplayTP(['12', '123'], ['34', '567'])); // [34, 3567]
*/
export function serverTPtoDisplayTP(tile, pixel) {
return [((parseInt(tile[0]) % 4) * 1000) + parseInt(pixel[0]), ((parseInt(tile[1]) % 4) * 1000) + parseInt(pixel[1])];
}
/** Negative-Safe Modulo. You can pass negative numbers into this.
* @param {number} a - The first number
* @param {number} b - The second number
* @returns {number} Result
* @author osuplace
* @since 0.55.8
*/
export function negativeSafeModulo(a, b) {
return (a % b + b) % b;
}
/** Bypasses terser's stripping of console function calls.
* This is so the non-obfuscated code will contain debugging console calls, but the distributed version won't.
* However, the distributed version needs to call the console somehow, so this wrapper function is how.
* This is the same as `console.log()`.
* @param {...any} args - Arguments to be passed into the `log()` function of the Console
* @since 0.58.9
*/
export function consoleLog(...args) {((consoleLog) => consoleLog(...args))(console.log);}
/** Bypasses terser's stripping of console function calls.
* This is so the non-obfuscated code will contain debugging console calls, but the distributed version won't.
* However, the distributed version needs to call the console somehow, so this wrapper function is how.
* This is the same as `console.error()`.
* @param {...any} args - Arguments to be passed into the `error()` function of the Console
* @since 0.58.13
*/
export function consoleError(...args) {((consoleError) => consoleError(...args))(console.error);}
/** Bypasses terser's stripping of console function calls.
* This is so the non-obfuscated code will contain debugging console calls, but the distributed version won't.
* However, the distributed version needs to call the console somehow, so this wrapper function is how.
* This is the same as `console.warn()`.
* @param {...any} args - Arguments to be passed into the `warn()` function of the Console
* @since 0.58.13
*/
export function consoleWarn(...args) {((consoleWarn) => consoleWarn(...args))(console.warn);}
/** Encodes a number into a custom encoded string.
* @param {number} number - The number to encode
* @param {string} encoding - The characters to use when encoding
* @since 0.65.2
* @returns {string} Encoded string
* @example
* const encode = '012abcABC'; // Base 9
* console.log(numberToEncoded(0, encode)); // 0
* console.log(numberToEncoded(5, encode)); // c
* console.log(numberToEncoded(15, encode)); // 1A
* console.log(numberToEncoded(12345, encode)); // 1BCaA
*/
export function numberToEncoded(number, encoding) {
if (number === 0) return encoding[0]; // End quickly if number equals 0. No special calculation needed
let result = ''; // The encoded string
const base = encoding.length; // The number of characters used, which determines the base
// Base conversion algorithm
while (number > 0) {
result = encoding[number % base] + result; // Find's the character's encoded value determined by the modulo of the base
number = Math.floor(number / base); // Divides the number by the base so the next iteration can find the next modulo character
}
return result; // The final encoded string
}
/** Decodes a number from a custom encoded string.
* @param {string} encoded - The encoded string
* @param {string} encoding - The characters to use when decoding
* @since 0.88.448
* @returns {number} Decoded number
* @example
* const encode = '012abcABC'; // Base 9
* console.log(encodedToNumber('0', encode)); // 0
* console.log(encodedToNumber('c', encode)); // 5
* console.log(encodedToNumber('1A', encode)); // 15
* console.log(encodedToNumber('1BCaA', encode)); // 12345
*/
export function encodedToNumber(encoded, encoding) {
let decodedNumber = 0; // The decoded number
const base = encoding.length; // The number of characters used, which determins the base
// For every character in the encoded string...
for (const character of encoded) {
const decodedCharacter = encoding.indexOf(character); // Decodes the character
// If no matching decode was found for this character...
if (decodedCharacter == -1) {
consoleError(`Invalid character '${character}' encountered whilst decoding! Is the decode alphabet/base incorrect?`);
}
decodedNumber = (decodedNumber * base) + decodedCharacter; // Adds the decoded character to the final number
}
return decodedNumber; // Returns the decoded number
}
/** Converts a Uint8 array to base64 using the browser's built-in binary to ASCII function
* @param {Uint8Array} uint8 - The Uint8Array to convert
* @returns {Uint8Array} The base64 encoded Uint8Array
* @since 0.72.9
*/
export function uint8ToBase64(uint8) {
let binary = '';
for (let i = 0; i &lt; uint8.length; i++) {
binary += String.fromCharCode(uint8[i]);
}
return btoa(binary); // Binary to ASCII
}
/** Decodes a base 64 encoded Uint8 array using the browser's built-in ASCII to binary function
* @param {Uint8Array} base64 - The base 64 encoded Uint8Array to convert
* @returns {Uint8Array} The decoded Uint8Array
* @since 0.72.9
*/
export function base64ToUint8(base64) {
const binary = atob(base64); // ASCII to Binary
const array = new Uint8Array(binary.length);
for (let i = 0; i &lt; binary.length; i++) {
array[i] = binary.charCodeAt(i);
}
return array;
}
/** Handles reading from the clipboard.
* Assume this only returns text.
* Assume this requires user input.
* @param {ClipboardEvent} [event=undefined] - (Optional) The clipboard event that triggered this to run
* @since 0.88.426
* @returns {string} The clipboard data as a string
*/
export async function getClipboardData(event = undefined) {
let data = ''; // Data from clipboard
// Try using the event, if any was provided
if (event) {
data = event.clipboardData.getData('text/plain');
}
if (data.length != 0) {return data;} // Continue only if data is still empty
// Try using the navigator clipboard
await navigator.clipboard.readText().then(text => {
data = text;
}).catch(error => {
consoleLog(`Failed to retrieve clipboard data using navigator! Using fallback methods...`);
});
if (data.length != 0) {return data;} // Continue only if data is still empty
// Try using IE clipboard
data = window.clipboardData?.getData('Text');
return data;
}
/** Calcualtes the relative luminance of an RGB value
* @param {Array&lt;Number, Number, Number>} array - The RGB values as an array
* @returns {Number} The relative luminance as a Number
* @since 0.88.180
*/
export function calculateRelativeLuminance(array) {
// Convert the 0-255 range to 0-1
const srgb = array.map(channel => {
channel /= 255;
return (channel &lt;= 0.03928) ? (channel / 12.92) : Math.pow((channel + 0.055) / 1.055, 2.4);
});
// https://en.wikipedia.org/wiki/Relative_luminance#Relative_luminance_and_%22gamma_encoded%22_colorspaces
return (0.2126 * srgb[0]) + (0.7152 * srgb[1]) + (0.0722 * srgb[2]);
}
/** Converts an RGB color to hexdecimal color.
* Octothorpe not included.
* @param {number | Array&lt;number, number, number>} red - The Red channel of the RGB color, or all three channels as an Array
* @param {number} [green] - The Green channel of the RGB color
* @param {number} [blue] - The Blue channel of the RGB color
* @returns {string} Hex color code as string
* @since 0.90.31
*/
export function rgbToHex(red, green, blue) {
if (Array.isArray(red)) {[red, green, blue] = red;} // Deconstruct the Array if an Array was passed in
return ((1 &lt;&lt; 24) | (red &lt;&lt; 16) | (green &lt;&lt; 8) | blue).toString(16).slice(1); // Packs it into a 24-bit integer, then converts it to base16.
}
/** Converts a hexdecimal color to an RGB color.
* Alpha channel not supported.
* @param {string} hex - Hex color code as string
* @returns {Array&lt;number, number, number>} RGB color as an Array
* @since 0.90.31
*/
export function hexToRGB(hex) {
hex = (hex[0] == '#') ? hex.slice(1) : hex; // Removes the octothorpe, if any
const packedIntRGB = parseInt(hex, 16); // Converts (base16) into an integer
return [(packedIntRGB >> 16 &amp; 255), (packedIntRGB >> 8 &amp; 255), (packedIntRGB &amp; 255)]; // Unpacks the integer into the RGB channels
}
/** Returns the coordinate input fields
* @returns {Element[]} The 4 coordinate Inputs
* @since 0.74.0
*/
export function selectAllCoordinateInputs(document) {
coords = [];
coords.push(document.querySelector('#bm-input-tx'));
coords.push(document.querySelector('#bm-input-ty'));
coords.push(document.querySelector('#bm-input-px'));
coords.push(document.querySelector('#bm-input-py'));
return coords;
}
/** Processes the palette used for Blue Marble.
* Each ID is sorted from smallest to largest.
* Color ID's are integers, which can be negative.
* Custom colors have been added for the Blue Marble purposes.
* Wplace palette colors have not been modified.
* @since 0.88.6
*/
export function colorpaletteForBlueMarble(tolerance) {
const colorpaletteBM = colorpalette; // Makes a copy
// Adds the Blue Marble color for "erased" and "other" pixels to the palette list
colorpaletteBM.unshift({ "id": -1, "premium": false, "name": "Erased", "rgb": [222, 250, 206] });
colorpaletteBM.unshift({ "id": -2, "premium": false, "name": "Other", "rgb": [ 0, 0, 0] });
const lookupTable = new Map();
// For each color in Blue Marble's palette...
for (const color of colorpaletteBM) {
if ((color.id == 0) || (color.id == -2)) continue; // skip Transparent or Other colors
// Target RGB values. These are exactly correct.
const targetRed = color.rgb[0];
const targetGreen = color.rgb[1];
const targetBlue = color.rgb[2];
// For each RGB value in the range of RGB values centered on the target RGB value for each channel...
for (let deltaRedRange = -tolerance; deltaRedRange &lt;= tolerance; deltaRedRange++) {
for (let deltaGreenRange = -tolerance; deltaGreenRange &lt;= tolerance; deltaGreenRange++) {
for (let deltaBlueRange = -tolerance; deltaBlueRange &lt;= tolerance; deltaBlueRange++) {
// Basically, we are making a "cube" around each target value.
// Say the tolerance is 3. The size of the cube will be ((3*2)+1)^3 which is 343 total.
// This means 343 colors will be Mapped as associated to the target color ID because 343 colors are in the "cube" surrounding and including the target color
// This specific deviation from the target RGB color values within the cube
const derivativeRed = targetRed + deltaRedRange;
const derivativeGreen = targetGreen + deltaGreenRange;
const derivativeBlue = targetBlue + deltaBlueRange;
// If it is impossible for the color to exist, then skip the color
if (derivativeRed &lt; 0 || derivativeRed > 255 || derivativeGreen &lt; 0 || derivativeGreen > 255 || derivativeBlue &lt; 0 || derivativeBlue > 255) continue;
// Packed into 32-bit integer like RGBA = 0xAARRGGBB with the alpha channel forced to be 255
// Also, it is forced to be an unsigned 32-bit integer
const derivativeColor32 = ((255 &lt;&lt; 24) | (derivativeBlue &lt;&lt; 16) | (derivativeGreen &lt;&lt; 8) | derivativeRed) >>> 0;
if (!lookupTable.has(derivativeColor32)) {
lookupTable.set(derivativeColor32, color.id);
}
}
}
}
}
return {palette: colorpaletteBM, LUT: lookupTable}
}
/** The color palette used by wplace.live
* @since 0.78.0
* @examples
* import utils from 'src/utils.js';
* console.log(utils[5]?.name); // "White"
* console.log(utils[5]?.rgb); // [255, 255, 255]
*/
export const colorpalette = [
{ "id": 0, "premium": false, "name": "Transparent", "rgb": [ 0, 0, 0] },
{ "id": 1, "premium": false, "name": "Black", "rgb": [ 0, 0, 0] },
{ "id": 2, "premium": false, "name": "Dark Gray", "rgb": [ 60, 60, 60] },
{ "id": 3, "premium": false, "name": "Gray", "rgb": [120, 120, 120] },
{ "id": 4, "premium": false, "name": "Light Gray", "rgb": [210, 210, 210] },
{ "id": 5, "premium": false, "name": "White", "rgb": [255, 255, 255] },
{ "id": 6, "premium": false, "name": "Deep Red", "rgb": [ 96, 0, 24] },
{ "id": 7, "premium": false, "name": "Red", "rgb": [237, 28, 36] },
{ "id": 8, "premium": false, "name": "Orange", "rgb": [255, 127, 39] },
{ "id": 9, "premium": false, "name": "Gold", "rgb": [246, 170, 9] },
{ "id": 10, "premium": false, "name": "Yellow", "rgb": [249, 221, 59] },
{ "id": 11, "premium": false, "name": "Light Yellow", "rgb": [255, 250, 188] },
{ "id": 12, "premium": false, "name": "Dark Green", "rgb": [ 14, 185, 104] },
{ "id": 13, "premium": false, "name": "Green", "rgb": [ 19, 230, 123] },
{ "id": 14, "premium": false, "name": "Light Green", "rgb": [135, 255, 94] },
{ "id": 15, "premium": false, "name": "Dark Teal", "rgb": [ 12, 129, 110] },
{ "id": 16, "premium": false, "name": "Teal", "rgb": [ 16, 174, 166] },
{ "id": 17, "premium": false, "name": "Light Teal", "rgb": [ 19, 225, 190] },
{ "id": 18, "premium": false, "name": "Dark Blue", "rgb": [ 40, 80, 158] },
{ "id": 19, "premium": false, "name": "Blue", "rgb": [ 64, 147, 228] },
{ "id": 20, "premium": false, "name": "Cyan", "rgb": [ 96, 247, 242] },
{ "id": 21, "premium": false, "name": "Indigo", "rgb": [107, 80, 246] },
{ "id": 22, "premium": false, "name": "Light Indigo", "rgb": [153, 177, 251] },
{ "id": 23, "premium": false, "name": "Dark Purple", "rgb": [120, 12, 153] },
{ "id": 24, "premium": false, "name": "Purple", "rgb": [170, 56, 185] },
{ "id": 25, "premium": false, "name": "Light Purple", "rgb": [224, 159, 249] },
{ "id": 26, "premium": false, "name": "Dark Pink", "rgb": [203, 0, 122] },
{ "id": 27, "premium": false, "name": "Pink", "rgb": [236, 31, 128] },
{ "id": 28, "premium": false, "name": "Light Pink", "rgb": [243, 141, 169] },
{ "id": 29, "premium": false, "name": "Dark Brown", "rgb": [104, 70, 52] },
{ "id": 30, "premium": false, "name": "Brown", "rgb": [149, 104, 42] },
{ "id": 31, "premium": false, "name": "Beige", "rgb": [248, 178, 119] },
{ "id": 32, "premium": true, "name": "Medium Gray", "rgb": [170, 170, 170] },
{ "id": 33, "premium": true, "name": "Dark Red", "rgb": [165, 14, 30] },
{ "id": 34, "premium": true, "name": "Light Red", "rgb": [250, 128, 114] },
{ "id": 35, "premium": true, "name": "Dark Orange", "rgb": [228, 92, 26] },
{ "id": 36, "premium": true, "name": "Light Tan", "rgb": [214, 181, 148] },
{ "id": 37, "premium": true, "name": "Dark Goldenrod", "rgb": [156, 132, 49] },
{ "id": 38, "premium": true, "name": "Goldenrod", "rgb": [197, 173, 49] },
{ "id": 39, "premium": true, "name": "Light Goldenrod", "rgb": [232, 212, 95] },
{ "id": 40, "premium": true, "name": "Dark Olive", "rgb": [ 74, 107, 58] },
{ "id": 41, "premium": true, "name": "Olive", "rgb": [ 90, 148, 74] },
{ "id": 42, "premium": true, "name": "Light Olive", "rgb": [132, 197, 115] },
{ "id": 43, "premium": true, "name": "Dark Cyan", "rgb": [ 15, 121, 159] },
{ "id": 44, "premium": true, "name": "Light Cyan", "rgb": [187, 250, 242] },
{ "id": 45, "premium": true, "name": "Light Blue", "rgb": [125, 199, 255] },
{ "id": 46, "premium": true, "name": "Dark Indigo", "rgb": [ 77, 49, 184] },
{ "id": 47, "premium": true, "name": "Dark Slate Blue", "rgb": [ 74, 66, 132] },
{ "id": 48, "premium": true, "name": "Slate Blue", "rgb": [122, 113, 196] },
{ "id": 49, "premium": true, "name": "Light Slate Blue", "rgb": [181, 174, 241] },
{ "id": 50, "premium": true, "name": "Light Brown", "rgb": [219, 164, 99] },
{ "id": 51, "premium": true, "name": "Dark Beige", "rgb": [209, 128, 81] },
{ "id": 52, "premium": true, "name": "Light Beige", "rgb": [255, 197, 165] },
{ "id": 53, "premium": true, "name": "Dark Peach", "rgb": [155, 82, 73] },
{ "id": 54, "premium": true, "name": "Peach", "rgb": [209, 128, 120] },
{ "id": 55, "premium": true, "name": "Light Peach", "rgb": [250, 182, 164] },
{ "id": 56, "premium": true, "name": "Dark Tan", "rgb": [123, 99, 82] },
{ "id": 57, "premium": true, "name": "Tan", "rgb": [156, 132, 107] },
{ "id": 58, "premium": true, "name": "Dark Slate", "rgb": [ 51, 57, 65] },
{ "id": 59, "premium": true, "name": "Slate", "rgb": [109, 117, 141] },
{ "id": 60, "premium": true, "name": "Light Slate", "rgb": [179, 185, 209] },
{ "id": 61, "premium": true, "name": "Dark Stone", "rgb": [109, 100, 63] },
{ "id": 62, "premium": true, "name": "Stone", "rgb": [148, 140, 107] },
{ "id": 63, "premium": true, "name": "Light Stone", "rgb": [205, 197, 158] }
];
</code></pre>
</article>
</section>
</div>
<br class="clear">
<footer>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Mar 17 2026 01:31:43 GMT+0000 (Coordinated Universal Time) using the Minami theme.
</footer>
<script>prettyPrint();</script>
<script src="scripts/linenumber.js"></script>
</body>
</html>