Formerly Radioactive Decay Calculator
Don't have the time to reference your periodic table while you do your mountain of questions assigned by your Physics teacher? This Google Chrome extension allows you to quickly search for elements and calculates alpha, beta+/- & electron capture decays.
This project was originally a site created for GryphHacks 2022 (University of Guelph's Hackathon). In 2024, I completely rewrote the code, clearing out most of the bugs, making it compatible with the Content Security Policy (CSP), and making it more cleaner and readable. Moreover, I added features like atom search and copy button.
To let me know if there are any issues, feel free to use the issues tab on this GitHub repo or emailing me at dereksong28@gmail.com. Licensed under the MIT License, available through thelicense.md file.
Extension created by Derek Song, 2024.
- Javascript for logic and calculations
- HTML for front end
- CSS for styles
- Bootstrap, for more consistent and faster styling
- JSON for Chrome extension identification
Moreover, additional tools used were:
- Figma - to sketch up user interface prototypes
- Adobe Illustrator - for vector graphics
- Adobe After Effects - for marketing videos
clipboardWrite. This permission is only used for the functions DecayCopy and AtomicSearchCopy, where decays / elements are copied to your keyboard from the click of your button.
index.htmlis the front end; where the user interacts with the projectstyles.csscontains style instructions for the index filebackground.jscontains most of the functions used for the project. It is used to find the variables inputted, do calculations, and prints outputatomicData.jscontains an array,const AtomicSymbol, which houses every elementmanifest.jsoncontains the manifest which is used by Google Chrome to identify the extension as well as permissions needed to use
index.html, each element contains an id, which the function callers use to know which function to call. For example,
input type="text" id="BetaPosShortFormOUT" class="form-control1" aria-label="Isotope number" aria-describedby="basic-addon2"
...is an input with the id "BetaPosShortFormOUT". This is read in background.js with
document.getElementById("BetaPosShortFormOUT").addEventListener("input", function() {
BetaPosAtomicSymbolRev(this.value);
});
Basically, if BetaPosShortFormOUT has an input, trigger the function BetaPosAtomicSymbolRev. As that function has one parameter, value, assign the value in id BetaPosShortFormOUT as that value.
For functions with multiple parameters, then it'll work a bit differently. For example, recall function AtomicSearchGroupName, which searches for an element in AtomicSymbol given the unknown atomic group and period.
This is the code given to call the function if AtomicSearchGroupNameIN is given and assign its variables:
document.getElementById("AtomicSearchGroupNameIN").addEventListener("input", function() {
var value = this.value;
var value2 = document.getElementById("AtomicSearchGroupPeriodIN").value;
AtomicSearchGroupName(value, value2);
});
If AtomicSearchGroupNameIN is called, then it will assign that value as value. It will also assign another value, value2, with the value of AtomicSearchGroupPeriodIN, the input of the period. It then calls the function with the 2 values using AtomicSearchGroupName(value, value2)
AtomicSearchAtomName triggers if an input, a string with the id AtomSearchAtomicNameIN is inputted.
function AtomicSearchAtomName (value){
// Function to print the name of an Atom. Input = AtomSearchAtomicNameIN (str)
var position = atomicSearch(AtomicSymbol, value, "name"); // Pass both arguments to aanFinder
if (position !== -1) {
var originalValuePosition = AtomicSymbol[position]; // Find position of the item
var groupName = groupSearch(originalValuePosition.group) // Find names for the groups
var blockName = blockSearch(originalValuePosition.group, originalValuePosition.period) // Find names for the block
// Output; a more concise version compared to the previous version
document.getElementById("AtomSearchAtomicSymbolOUT").innerHTML = originalValuePosition.shortform;
document.getElementById("AtomSearchAtomicNumberOUT").innerHTML = originalValuePosition.aanConst;
document.getElementById("AtomSearchAtomicNameOUT").innerHTML = originalValuePosition.name;
document.getElementById("AtomicSearchGroupNameOUT").innerHTML = groupName[0];
document.getElementById("AtomicSearchGroupNameOUTalt").innerHTML = groupName[1];
document.getElementById("AtomicSearchGroupPeriodOUT").innerHTML = originalValuePosition.period;
document.getElementById("AtomSearchAtomicMassOUT").innerHTML = originalValuePosition.avgMass;
document.getElementById("AtomicBlockOUT").innerHTML = blockName[0];
document.getElementById("AtomicBlockOUTalt").innerHTML = blockName[1];
}
}
The function identifies the unknown atomic element by passing calling atomicSearch (explained below), with the value, and notes that the value is the name of the atomic value.
If the position is valid (which if it passes if (position !== -1) {, where -1 is an invalid or missing element), then it will assign that position as the variable originalValuePosition. It will find the group by calling groupSearch with the group parameter of originalValuePosition.group, as well as find the block by calling the blockName function.
Other functions may also have a resultant variable, which calculates the outcome element given a decay. For example, in the function BetaPosAtomicNumber, resultant is: var resultant = AtomicSymbol[position-1]. It finds the n-th element in AtomicSymbol, where n is the position of the original element subtracted by one (i.e. the effects of a beta-positive decay).
The values are then outputted by calling the ID of all of the appropriate elements and assigning it as
- the appropriate value in either
originalValuePositionorresultant - the n-th element in an array (e.g.
blockName[0])) if the output of the function is an array. Refer to specific function documentation for which array to use
.innerHTML and others call for the .value. In general,
.innerHTMLis used for any HTML element whose output is in aspanelement.valuesis used for any HTML element whose output is in ainputelement. Generally used in elements like atomic number, short form, or mass.
atomicSearch is an important function as it searches through array atomicSymbol and finds the requested element. Parameters are:
AtomicSymbol, which is the array that houses all of the elements (const)value, which is the value to search for (str or int)searchVal, which defines what to search for. Only useaanConst,atomSearch,name,mass(str)value2, another value to search for. Only used if searchVal =atomSearch(str or int)
For any string inputs, there is usually a snippet of code after the if structure which looks like value = value.charAt(0).toUpperCase() + value.slice(1).toLowerCase();. This turns the first letter of the string into uppercase, and all of the others to lowercase, which is the style used in the array AtomicSymbol. (e.g. hEliuM turns to Helium).
Then, a for loop is used.
for (var i = 0; i < AtomicSymbol.length; i++) { // Search for item matching value at "i". If "i" == value, get its index, else add 1 to i.
if (AtomicSymbol[i].shortform === value) {
return i; // Return the index of the found element
}
}
return -1; // Return -1 if no matching element is found
The for loop defines a value i and sets it as zero. This tells it to start at position zero, and go up to the length of AtomicSymbol. If the shortform of AtomicSymbol at position i holds true, then return the value of i. Else, add 1 to i and continue.
If i < AtomicSymbol.length is reached, then return -1. The other functions will interpret a value of -1 as a missing or invalid element.
For searchVal === atomSearch, where 2 values are given, a slightly different if structure is used.
if (AtomicSymbol[i].group === parseInt(value) && AtomicSymbol[i].period === parseInt(value2)) { // Variable "value" represents group assignment, variable "value2" represents period.
return i; // Return the index of the found element
} else if (AtomicSymbol[i].group === value && AtomicSymbol[i].period === parseInt(value2)) { // Special coniditon if "N/A" is inputted. Does not convert value into int.
return i; // Return the index of the found element
}
If AtomicSymbol's group at position i equals value, and the AtomicSymbol's period at position i equals to value2 is also true, return i. Additionally, if value is a string (only happens if "N/A is inputted), it omits the parseInt(value) only for value, which converts the str to int.
atomicData.js. It looks roughly like this:
const AtomicSymbol = [ // An array of Atomic elements. Use = AtomicSymbol[]. name: Name of element (str); shortform: Element intials (str); aanConst: Atomic number (int) ; group: Group on periodic table (int) ; period: Period on periodic table (int) ; avgMass: the average mass of an element (float)
{
name: "N/A",
shortform: "N/A",
aanConst: 0,
group: -1,
period: -1,
avgMass: -1,
},
{
name: "Hydrogen",
shortform: "H",
aanConst: 1,
group: 1,
period: 1,
avgMass: 1.0078,
},
...(etc)
nameis the full name of the element. Capitalize the first letter and make sure the other letters are lowercase (N/Ais the only special exception to this rule.) The functions are programmed to automatically convert string inputs to this format. (e.g. "Hydrogen") (str)shortformis the abbreviation of the element. Capitalize the first letter and make sure the other letters are lowercase (N/Ais the only special exception to this rule.) The functions are programmed to automatically convert string inputs to this format. (e.g. "He") (str)aanConstis the atomic number of the element (int).groupis the group of the element (int).periodis the period of the element (int).avgMassis the average mass of the element (float).
To reference, use AtomicSymbol[i].element, where i is the position of the element in the list (technically the atomic number), and .element is the element you want to search for.
Both functions are similar as they compare one/multiple values, and return a set of variables in an array.
- blockName takes in
groupandperiodand assigns the appropriate block and azimuthal quantum number. Referenceresult[0]for block, andresult[1]for azNum, assuming thatvar result = blockSearch(group, period) - groupName takes in
groupand assigns appropriate group and IUPAC name. To reference, callresult[0]for groupName, andresult[1]for IUPACname, assuming thatvar result = groupSearch(group)
DecayCopycopies alpha, beta +/-, and electron capture decays. It takes in one value which indicates the type of decay. (str)AtomSearchCopycopies atomic search. It takes no value.
The functions first call the HTML elements in the selected decay type. It creates a const named textCopy, which is a text area in the document. It then assembles the sentence, usually with a statement like
textCopy.value = atomicName + "\nShort form: " + atomicSymbol + "\nAtomic number: " + atomicNumber + "\nGroup: " + atomicGroup + "\nIUPAC group name: " + atomicGroupAlt +"\nPeriod: " + atomicPeriod + "\nBlock: " + atomicBlock + "\nAzimuthal quantum number: " + atomicBlockAlt + "\nAverage mass: " + atomicMass
For DecayCopy an if statement is used, comparing the type of element. It then assembles the sentence according to the decay.
Next, textCopy is appended to the node of the document (document.body.appendChild(textCopy);). It is then selected (textCopy.select();), and the clipboard is instructed to copy the value (navigator.clipboard.writeText(textCopy.value)). After that is done, the node is cleared (document.body.removeChild(textCopy);).
Similar to the "identifying" functions, these functions tell the webpage what to hide or load. For example, the function below listens if AtomSearchbtn is clicked or not, and if so, defines each element as its own variable, then shows AtomSearch and hides the others.
document.getElementById('AtomSearchbtn').addEventListener('click', function() {
// Funciton to show AtomSearch and hide other elements upon clicking AtomSearchbtn. Inputs = none
// Variables for elements
var BetaPositive = document.getElementById('BetaPositive');
var Alpha = document.getElementById('Alpha');
var BetaNegative = document.getElementById('BetaNegative');
var ElectronCapture = document.getElementById('ElectronCapture');
var AtomSearch = document.getElementById('AtomSearch');
// Hides/show approprate elements
BetaPositive.style.display = 'none';
Alpha.style.display = 'none';
BetaNegative.style.display = 'none';
ElectronCapture.style.display = 'none';
AtomSearch.style.display = 'block'
});
In general, these HTML ids correspond to:
Alpha- alpha decay element (button to show:Alphabtn)AtomSearch- atom search element (button to show:AtomSearchbtn)BetaPositive- beta positive decay element (button to show:BetaPositivebtn)BetaNegative- beta negative decay element (button to show:BetaNegativebtn)ElectronCapture- electron capture (button to show:ElectronCapturebtn)
To show an element, set the element's .style.display to equal to block. To hide, set as none.
href into an a tag to link it to another page, this isn't supported in a Google Chrome extension. Hencewhy this piece of code exists
document.getElementById('GitHub').addEventListener('click', function() {
// Link to github repo
chrome.tabs.update({ url: 'https://github.com/twotoque/physicscalculator/' });
});
This code listens to if an HTML id named GitHub is clicked. If it is, then Chrome is instructed to update the tab to go to the corresponding link, in this case https://github.com/twotoque/physicscalculator/.