Hi there! I am delighted to talk about a web application called QuantumX, which I created for an internship at SashiDo. Basically, the application helps you in learning the first 30 elements of Modern Periodic Table, in the order of increasing atomic number, along with it's properties such as atomic masses, group numbers and electronic configurations. The periodic table of elements is widely used in the field of Chemistry to look up chemical elements as they are arranged in a manner that displays periodic trends and correlations in the chemical properties of the elements. Moreover, every science student must be aware of the properties of first 30 elements at the least to crack any entrance exam. "QuantumX" will be helpful to learn and memorize the elements as it pictorially represents the element's symbol and properties. I used Teachable Machine to detect the element from an image model. Essentially, when you show a picture of element's symbol, the full name of the element is detected.
Before we could see how to create this simple application, make sure to create an account on SashiDo. It is a company that provides very pleasing and lovely backend service platform. Once your account is created, you will be given sufficient time to prepare and create your project.
Table of contents
- About the project
- Teachable Machine
- Create a responsive website
- Connecting the App with SashiDo by Parse
- User Registration (Login and Sign in)
- How to use Teachable Machine Image Model in the website
- Showing and hiding the properties of elements
- Video of the working of QuantumX
- Closing Remarks
- Useful links
About the project
The name "QuantumX" derives from the word Quantum, which is the smallest unit of energy or matter, and X denotes the chemical symbol of the elements.
I have used HTML5, CSS and JavaScript to create a responsive website wherein an image model(ML model) is used to detect elements. That is, the ML model uses Teachable Machine to get the input element's symbol either through webcam or image file uploaded, and provides the details of that element.
The video demo:
Teachable Machine
This is one of the interesting parts which makes sense to your whole idea in creating this web application. "Teachable Machine" may sound a bit new to you, but once you work with it, you will start playing with it. Teachable Machine is a web-based tool that helps in creating your ML models yourself even if you are just a beginner. All it requires is the data set that you provide to train your model to recognize variety of information.
To create your own exciting ML model, follow these simple steps:
Be ready with your data set
Gather and categorize the input files in a location. The more pictures you provide your model the more it's precision in detecting an image will be.
In my case, the data set for uploading files will be looking like this:
Create and train your model
Click on this link. Name the classes with full name of the symbol such as . Take four elements at a time, in the order of increasing atomic number, so it would be easier for learners to study about them. Taking all thirty elements at once will also delay the training process.
Provide both webcam images and image files to your model. For webcam inputs, use white cards and letters from print outs. Check how I have used these in "this" section. You can also try other means of exhibiting these symbols as you please.
Click on Train Model to train your model. Don't switch tabs at this time.
Export the model
Once your model is trained, play with it by testing different elements and it's confidence in answers.
Now, it's time to export your model. Click on Export Model and click on Upload my model.
After this, copy the JavaScript code in Tensorflow.js and the sharable link for later use:
Make sure that you save all the image model sharable links in a notepad for later use. We will be seeing how to use these links in "this" section.
Create a responsive website
For a good user interface, I suggest you to design and structure your website in Figma. It is an awesome prototyping tool which is completely free to use. Also, you can get the code in CSS, iOS and Android for each component of the design. When you get ready with UI of your website, start creating the website in Visual Studios. If you haven't downloaded yet, click here to download the latest version. Click on the "Community Version" as shown below:
Use Visual Studios to create the entire application, as it supports all functions needed to execute Teachable Machine and Parse. Create a folder to save all files in HTML5, CSS and JavaScript. Maintain a separate file for images and icons.
Do watch the tutorial videos in YouTube for creating a website. However, If you are just a beginner and you want know how to build a website from the basic, click on this tutorial.
To make your website respond to the user's behavior and environment based on screen size, platform and orientation, it is a good practice to create a Responsive Website. Make sure that you use CSS flexbox in all web pages.
Add the following tag to all your web pages, to create a responsive website:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
In CSS design, use the following code to change designs of different screen lengths:
@media only screen and (max-width: 700px)
{
/*code*/
}
In my case, I have used "max-width: 700px". Try giving different values for "max-width" that is compatible with your web page. To know more about this CSS syntax check out the CSS @media rule.
Connecting the App with SashiDo by Parse
- After creating the account on SashiDo, go to the dashboard, Click on Create New App and follow these instructions.
- In the "Getting Started" page in SashiDo , copy the code in JavaScript and paste it in the "app.js" file. This code will connect your application with SashiDo.
We will use the same "app.js" file to function registration pages using Parse, in the next section.
- Add this Parse script at the bottom of your "index.html" file, which will contain
<script src="app.js" type="text/javascript"></script>
.
<script src="https://cdnjs.cloudflare.com/ajax/libs/parse/3.1.0/parse.min.js"></script>
User Registration
- Create a form in "index.html" page that has options to "Log In" and "Sign Up":
<div id="form-container">
<form id="form">
<div>
<div class="name1"><input type="text" id="username" placeholder="Username" name="username"></div>
<div class="name2"><input type="password" id="pass" placeholder="Password" name="pass"></div>
</div>
</form>
<div>
<div id="buttonsContainer">
<div class="click1"><button type="button" id="login">Log In</button></div>
<div class="click2"><button type="button" id="sign">Sign Up</button></div>
</div>
</div>
<span id="returnMessage"></span>
</div>
Make sure that you have added the Parse script that implements all functions in Parse.
- Create functions to invoke Log In and Sign Up requests in Parse. I recommend you to see Parse JavaScript Guide to understand how to use Parse for user registration.
// Registration Pages
async function logIn() {
const username = document.getElementById("username").value;
const pass = document.getElementById("pass").value;
const formContainer = document.getElementById("form-container");
const container = document.getElementById("container");
let span = document.getElementById("returnMessage");
const onFulfilled = () => {
span.textContent = "Successful Log In!";
window.open("website.html", "_self");
};
const onRejected = () => {
span.textContent = "Incorrect username or password";
};
const user = await Parse.User.logIn(username, pass).then(
onFulfilled,
onRejected
);
}
async function signUp() {
const username = document.getElementById("username").value;
const pass = document.getElementById("pass").value;
let span = document.getElementById("returnMessage");
const user = new Parse.User();
user.set("username", username);
user.set("password", pass);
try {
await user.signUp();
span.textContent = "Successfully signed Up";
window.open("website.html", "_self");
} catch (error) {
span.textContent = "Error: " + error.code + " " + error.message;
}
}
// Add on click listener to call the create parse user function
document.getElementById("sign").addEventListener("click", async function () {
signUp();
});
// Add on click listener to call the create parse user function
document.getElementById("login").addEventListener("click", async function () {
logIn();
});
- When you execute the Parse code to connect SashiDo, you can see the updates in the "session" section in the Database Browser. Similarly, when you perform "Log In" and "Sign Up" operations, you can view the updated user accounts in the Browser:
How to use Teachable Machine Image Model in the website
We need around eight ML image models to cover all thirty elements. We will use one model for 4 elements. Now, let's see the working of teachable machine functions for the first 4 elements: Hydrogen, Helium, Lithium and Beryllium.
- As you can see, we need Teachable Machine functions to carry out the working of "Start Webcam" and "Upload Image". Build a HTML page for each ML model like shown here:
<div class="container">
<div class="padding1">
<div class="headContainer"><span class="v248_12">H to Be</span></div>
</div>
<div class="buttonAll">
<button type="button" onclick="startCamHandler()" id="camButton">Start Webcam</button>
<button type="button" onclick="startUpHandler()" id="upButton">Upload Image</button>
</div>
<div id="game-container">
<div id="webcam-container" class="d-none"></div>
<input type="file" id="inp" class="d-none">
<canvas id="canvas" class="d-none"></canvas>
<div id="label-container" class="d-none"></div>
<div id="fullAnswer" class="d-none"></div>
</div>
<form method="get" action="website.html">
<button class="back" type="submit">Back</button>
</form>
</div>
- It is very important to add these script tags to execute the ML model:
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.3.1/dist/tf.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@teachablemachine/image@0.8/dist/teachablemachine-image.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/parse/3.1.0/parse.min.js"></script>
- In the JS file, add the Teachable Machine model URL in a constant :
// H to Be elements
//Teachable Machine model Url
const URL = "https://teachablemachine.withgoogle.com/models/XTs3NXuAG/";
- Now, add the following code to start and stop webcam:
let model, webcam, labelContainer, maxPredictions;
//is started Webcam flag
let startCamFlag = true;
//is started Upload flag
let startUpFlag = true;
let camButton = document.getElementById("camButton"), upButton = document.getElementById("upButton");
function startCamHandler() {
if (startUpFlag) {
if (startCamFlag) init();
else stop();
startCamFlag = !startCamFlag;
}
}
function startUpHandler() {
if (startCamFlag) {
if (startUpFlag) openUploadImage();
else closeUploadImage();
startUpFlag = !startUpFlag;
}
}
Provide input through webcam
- In this "init()" function, check whether flip needs to be given. I did not use the flip as it will be inappropriate with letters/symbols.
// Load the image model and setup the webcam
async function init() {
const modelURL = URL + "model.json";
const metadataURL = URL + "metadata.json";
// load the model and metadata
// Refer to tmImage.loadFromFiles() in the API to support files from a file picker
// or files from your local hard drive
// Note: the pose library adds "tmImage" object to your window (window.tmImage)
model = await tmImage.load(modelURL, metadataURL);
maxPredictions = model.getTotalClasses();
// Convenience function to setup a webcam
const flip = true; // whether to flip the webcam
webcam = new tmImage.Webcam(200, 200); // width, height, flip
await webcam.setup(); // request access to the webcam
await webcam.play();
window.requestAnimationFrame(loop);
// append elements to the DOM
document.getElementById("webcam-container").appendChild(webcam.canvas);
labelContainer = document.getElementById("label-container");
labelContainer.appendChild(document.createElement("div"));
//Changing button text
camButton.textContent = "Stop";
//Showing containers
document.getElementById("webcam-container").className = "";
document.getElementById("label-container").className = "";
document.getElementById("fullAnswer").className="";
}
- Use the following function to stop webcam:
async function stop() {
await webcam.stop();
document.getElementById("webcam-container").removeChild(webcam.canvas);
labelContainer = document.getElementById("label-container");
console.log(labelContainer.children);
labelContainer.removeChild(labelContainer.children[0]);
camButton.textContent = "Start Webcam";
//Change Answer
document.getElementById("fullAnswer").innerHTML="";
//Hiding containers
document.getElementById("webcam-container").className = "d-none";
document.getElementById("label-container").className = "d-none";
document.getElementById("fullAnswer").className="d-none";
}
When "Stop webcam" is clicked, the answers will be removed from the container.
- Now, create the loop to update the webcam inputs, so we will get the corresponding prediction that is equivalent with the image shown in webcam.
async function loop() {
webcam.update(); // update the webcam frame
await predict();
window.requestAnimationFrame(loop);
}
- Now, create the function to predict the class that gets highest probability in being similar to the image shown in webcam. Then, the corresponding name, atomic number, atomic mass and electronic configuration of the class are displayed.
// run the webcam image through the image model
async function predict(imageModel = webcam.canvas) {
let highestProbability;
let lastProbability = 0;
// predict can take in an image, video or canvas html element
const prediction = await model.predict(imageModel);
console.log(prediction);
for (let i = 0; i < maxPredictions; i++) {
if (prediction[i].probability.toFixed(2) > lastProbability)
highestProbability = i;
lastProbability = prediction[i].probability.toFixed(2);
}
const className1 = prediction[highestProbability].className;
let classNameShow = className1;
//document.getElementById("label-container").innerHTML=classNameShow;
labelContainer.childNodes[0].innerHTML = classNameShow;
//Predict the answer
if(classNameShow=="Hydrogen"){
document.getElementById("fullAnswer").innerHTML="Atomic Number: 1 <br> Atomic Mass: 1.00797 amu <br> Group: 1 <br> Electronic Configuration: 1s"+'1'.sup();
}
else if(classNameShow=="Helium"){
document.getElementById("fullAnswer").innerHTML="Atomic Number: 2 <br> Atomic Mass: 4.00260 amu <br> Group: 18 <br> Electronic Configuration: 1s"+'2'.sup();
}
else if(classNameShow=="Lithium"){
document.getElementById("fullAnswer").innerHTML="Atomic Number: 3 <br> Atomic Mass: 6.941 amu <br> Group: 1 <br> Electronic Configuration: [He] 2s"+'1'.sup();
}
else if(classNameShow=="Beryllium"){
document.getElementById("fullAnswer").innerHTML="Atomic Number: 4 <br> Atomic Mass: 9.01218 amu <br> Group: 2 <br> Electronic Configuration: [He] 2s"+'2'.sup();
}
}
Observe this code again and notice the predicted class name. This class name is linked with Atomic number, Atomic mass, group number and electronic configuration. For exhibiting these properties, remember to create a separate container in HTML and update it's content by changing it's class name.
To show the full content
//Showing containers
document.getElementById("webcam-container").className = "";
document.getElementById("label-container").className = "";
document.getElementById("fullAnswer").className="";
To hide the content
//Hiding containers
document.getElementById("webcam-container").className = "d-none";
document.getElementById("label-container").className = "d-none";
document.getElementById("fullAnswer").className="d-none";
Provide input by uploading images
- Functions used in uploading images involves showing the answer whenever file is chosen, otherwise it is hidden or removed.
function openUploadImage() {
//Showing elements
document.getElementById("inp").className = "";
document.getElementById("canvas").className = "";
document.getElementById("fullAnswer").className="";
//Changing button text
upButton.textContent = "Close";
}
function closeUploadImage() {
labelContainer = document.getElementById("label-container");
let canvas = document.getElementById("canvas"),input = document.getElementById("inp");
//Hiding input
input.className = "d-none";
input.value = null;
//Removing Label
labelContainer.className = "d-none";
if (labelContainer.children.length > 0)
labelContainer.removeChild(labelContainer.children[0]);
canvas.className = "d-none";
//Removing and changing the answer
document.getElementById("fullAnswer").innerHTML="";
document.getElementById("fullAnswer").className="d-none";
//Clear canvas
const context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
upButton.textContent = "Upload Image";
}
- Now, we should implement the upload image handler, the process is similar to the previous one. Basically, we caught the image on the input file, drew it into a canvas and then requested the Teachable Machine prediction for the element.
//Uploading Image
document.getElementById("inp").onchange = function (e) {
var img = new Image();
img.onload = draw;
img.onerror = failed;
img.src = window.URL.createObjectURL(this.files[0]);
};
async function draw() {
var canvas = document.getElementById("canvas");
canvas.width = this.width;
canvas.height = this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
const modelURL = URL + "model.json";
const metadataURL = URL + "metadata.json";
model = await tmImage.load(modelURL, metadataURL);
maxPredictions = model.getTotalClasses();
labelContainer = document.getElementById("label-container");
labelContainer.appendChild(document.createElement("div"));
labelContainer.className = "";
await predict(canvas);
}
function failed() {
console.error("The provided file couldn't be loaded as an Image media");
}
Video of the working of QuantumX
Closing Remarks
Initially, I was taking a lot of time to get a good idea to be implemented with SashiDo and Teachable machine. As I have a Chemistry class in my college along with other Computer Sciences, I had decided to integrate them in some way. Then I decided to implement the modern periodic table elements with Techable machine's image model that not only integrates with Chemistry but also helps beginners to memorize these elements with properties such as atomic number, atomic mass, group number and electronic configuration which are more frequently used in exams.
While implementing the idea, I had to learn JavaScript and a little bit of Parse, which gave me confidence to proceed with my project. Whenever I was struck in between, I would mail SashiDo about any errors after which Veselina Staneva from SashiDo would help me with the errors. I am ever thankful for SashiDo, Vesi and Irena for giving me this opportunity to bring out my own creative ideas and helping me with creating it. I want to thank Vesi Staneva specially for giving me more than enough time to complete the project as well as this tutorial. Also, I want to thank my lovely and smart sister, Vaishnavi for helping me in anything at anytime during this intern.
I hope this tutorial helps you in implementing the similar ideas that you want to do with teachable machine in your websites. I very much recommend you to use SashiDo as it provides backend, ready to use API's, cloud service and UI/UX design editors in dashboard itself. Not only that it provides a database to store and manipulate the data for login or signup and others for your application. They are friendly and sociable people who will guide you throughout the project. It is a place to see when you want to create and develop applications in your favourite programming languages. Just concentrate on the idea and implement it then SashiDo will handle the rest for you!
Useful links
Project in GitHub
Web-App link
SashiDo
SashiDo Getting Started Guide
Build a responsive website
Build a responsive website from scratch
Teachable Machine
The Awesome Teachable Machine list
Parse Documentation
Top comments (1)
Hi Haripriya, my name is Safina Firdaus, a chemistry education undergraduate student at Universitas Negeri Jakarta, Indonesia. I have read your article and am interested in creating elements in the periodic table using SashiDo and Teachable Machine as well but in the Indonesian version. So I have permission to create something similar to this for the purpose of a course assignment. Thank you for this tutorial.