Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
233 changes: 233 additions & 0 deletions extensions/DogeisCut/FormatNumbers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
// Name: Format Numbers
// ID: dogeiscutformatnumbers
// Description: Format large numbers into AD standard, fixed decimal, comma separated, or scientific notation.
// By: DogeisCut <https://scratch.mit.edu/users/dogeiscut/>
// License: MIT

// Version V.2.0.2

// TODO:
// - Editor Icon
// - BigInt Support
// - Time notation, decimal count defines how many milliseconds show.

(function (Scratch) {
"use strict";

const Cast = Scratch.Cast;

const Formats = {
AD_STANDARD: "AD standard",
FIXED_DECIMAL: "fixed decimal",
COMMA_SEPERATED: "comma separated",
SCIENTIFIC_NOTATION: "scientific notation",
};

class FormatNumbers {
constructor() {
this.notation = "AD standard";
this.decimalPlaces = 2;
}

convertToADStandard(number, decimalPlaces = 2) {
if (typeof number !== "number" || isNaN(number)) {
return "Invalid Input";
}

if (!isFinite(number)) {
return number.toString();
}

if (number === 0) {
return "0";
}

const kMBd = [
"",
"K",
"M",
"B",
"T",
"Qa",
"Qt",
"Sx",
"Sp",
"Oc",
"No",
"Dc",
];
const unitPrefixes = ["U", "D", "T", "Qa", "Qt", "Sx", "Sp", "O", "N"];
const tensPrefixes = [
"Dc",
"Vg",
"Tg",
"Qd",
"Qi",
"Se",
"St",
"Og",
"Nn",
];
const hundredsPrefixes = [
"Ce",
"Dn",
"Tc",
"Qe",
"Qu",
"Sc",
"Si",
"Oe",
"Ne",
];
const tier2Illions = ["MI", "MC", "NA", "PC", "FM", "AT", "ZP"];
const tier2Cutoff = 3003 * tier2Illions.length;
if (Math.log10(Math.abs(number)) > tier2Cutoff) {
return `Il(${number})`;
}

if (Math.abs(number) < 1000) {
return number.toFixed(decimalPlaces).replace(/\.?0+$/, "");
}

const tier = Math.max(0, Math.floor(Math.log10(Math.abs(number)) / 3));

if (tier <= 11) {
const scaledNumber = number / Math.pow(10, tier * 3);
return (
scaledNumber.toFixed(decimalPlaces).replace(/\.?0+$/, "") + kMBd[tier]
);
}

const illionNumber = Math.floor(Math.log10(Math.abs(number)) / 3);
let illionString = "";

if (illionNumber <= 999) {
const hundreds = Math.floor(illionNumber / 100);
const tens = Math.floor((illionNumber % 100) / 10);
const units = illionNumber % 10;

illionString =
(hundreds > 0 ? hundredsPrefixes[hundreds - 1] : "") +
(tens > 0 ? tensPrefixes[tens - 1] : "") +
(units > 0 ? unitPrefixes[units - 1] : "");
} else {
const tier2Index = Math.floor(illionNumber / 1000);
const tier2Remainder = illionNumber % 1000;

if (tier2Index <= tier2Illions.length) {
illionString = tier2Illions[tier2Index - 1];
} else {
return `Il(${number})`;
}

if (tier2Remainder > 0) {
const hundreds = Math.floor(tier2Remainder / 100);
const tens = Math.floor((tier2Remainder % 100) / 10);
const units = tier2Remainder % 10;

const remainderString =
(hundreds > 0 ? hundredsPrefixes[hundreds - 1] : "") +
(tens > 0 ? tensPrefixes[tens - 1] : "") +
(units > 0 ? unitPrefixes[units - 1] : "");
illionString = remainderString + "-" + illionString;
}
}

const scaledNumber =
number / Math.pow(10, Math.floor(Math.log10(Math.abs(number)) / 3) * 3);
return (
scaledNumber.toFixed(decimalPlaces).replace(/\.?0+$/, "") +
" " +
illionString
);
}

convertToCommaSeparated(number, decimalPlaces = 2) {
return number
.toFixed(decimalPlaces)
.replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
}

convertToScientificNotation(number, decimalPlaces = 2) {
return number.toExponential(decimalPlaces);
}

formatNumber(args) {
const decimals = Math.max(0, Math.min(100, Cast.toNumber(args.DECIMALS)));
switch (args.NOTATION) {
case Formats.AD_STANDARD:
return this.convertToADStandard(Cast.toNumber(args.NUM), decimals);
case Formats.COMMA_SEPERATED:
return this.convertToCommaSeparated(
Cast.toNumber(args.NUM),
decimals
);
case Formats.SCIENTIFIC_NOTATION:
return this.convertToScientificNotation(
Cast.toNumber(args.NUM),
decimals
);
default:
return Cast.toNumber(args.NUM).toFixed(decimals);
}
}

getInfo() {
return {
id: "formatNumbers",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, should contain username and match the ID at the top

name: Scratch.translate("Format Numbers"),
color1: "#419873",
color2: "#4CA981",
blocks: [
{
opcode: "formatNumber",
text: Scratch.translate(
"format number [NUM] to notation [NOTATION] with [DECIMALS] decimal places"
),
blockType: Scratch.BlockType.REPORTER,
arguments: {
NUM: {
type: Scratch.ArgumentType.NUMBER,
defaultValue: 1000,
},
NOTATION: {
type: Scratch.ArgumentType.STRING,
menu: "notationOptions",
defaultValue: "AD standard",
},
DECIMALS: {
type: Scratch.ArgumentType.NUMBER,
defaultValue: 2,
},
},
},
],
menus: {
notationOptions: {
acceptReporters: false,
items: [
{
text: Scratch.translate("AD standard"),
value: Formats.AD_STANDARD,
},
{
text: Scratch.translate("fixed decimal"),
value: Formats.FIXED_DECIMAL,
},
{
text: Scratch.translate("comma separated"),
value: Formats.COMMA_SEPERATED,
},
{
text: Scratch.translate("scientific notation"),
value: Formats.SCIENTIFIC_NOTATION,
},
],
},
},
};
}
}

Scratch.extensions.register(new FormatNumbers());
})(Scratch);
1 change: 1 addition & 0 deletions extensions/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,6 @@
"itchio",
"gamejolt",
"obviousAlexC/newgroundsIO",
"DogeisCut/FormatNumbers",
"Lily/McUtils" // McUtils should always be the last item.
]
Binary file added images/DogeisCut/FormatNumbers.png
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically extension images aren't supposed to contain text because of translation reasons, but I think this one is okay because it uses Arabic numerals which are (generally speaking) somewhat universal? I don't know. Second opinion would be great

Copy link
Collaborator

@CST1229 CST1229 Mar 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo numbers wouldn't be considered text for thumbnails.
they are the exact same Arabic numberals in all of Scratch's languages and they already exist in several extension thumbnails (base, bitwise). i think it's good

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo numbers aren't considered text for thumbnails. they are Arabic numberals in all of Scratch's languages and they already are in several extension thumbnails (base, bitwise). i think it's good

That's what I was thinking too

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

though ideally this should be an SVG

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would've liked to make this an SVG but unfortunately, I don't believe Dillon has an SVG version. Guess I could try to re-create it if it is really necissary?

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions images/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,3 +320,6 @@ All images in this folder are licensed under the [GNU General Public License ver

## CubesterYT/KeySimulation.svg
- Created by [@SharkPool-SP](https://github.com/SharkPool-SP/)

## DogeisCut/FormatNumbers.png
- Created by [@Dillon](https://github.com/DillonRGaming)