KanvasWire
Contributors
- Hieu Nguyen (HieuHongHao)
- Peter Phan (PPhan-sil)
- Phat Nguyen (PeterNg15)
Overview
KanvasWire is a platform that enable users to post their project ideas to collaborate with like-minded individuals. KanvasWire offers a variety of services for collaboration such as: a comment section for discussion, an interactive canvas to illustrate their ideas, and a chat to communicate with collaborators. The novelty of our platform comes in the form of combining those services together into one innovative product. Our platform’s target audience are people with a STEM and tech background and we made sure to address their needs through our website. For instance, we implemented a chat feature to enable users to send equations using LaTeX as we believe this would improve communication and enhance productivity.
Building Components from Scratch
For this project we were not allowed to use any javascript frameworks such as Angular, React, or Vue. This made refactoring components and templates for web pages difficult. To solve this issue we created our own templating engine inspired by EJS. Our engine allowed us to efficiently build components with data we give it.
Any repeated HTML component can be refactored to its own HTML file like so:
<!-- Comment.html template -->
<li class="list-group-item px-0 pt-3 pb-0 d-flex cat-bg-light cat-text-light">
<div class="align-top">
<img src="${avatar}" alt="Logo" class="rounded-circle">
</div>
<div class="ps-3 pe-4">
<div class="d-flex">
<p class="m-0 me-2">${username}</p>
<p class="fs-6 fw-lighter m-0">- ${date}</p>
</div>
<p class="fw-light">${content}</p>
</div>
</li>
A placeholder variable is denoted by the notation of ”${variable}“. In the above example there is a placeholder for the commenter’s profile picture (${avatar}), their username (${username}), the date (${date}), and the contents of the comment (${content}).
Using the above template can be done like so:
const commentsDiv = document.getElementById("comments");
const commentHTML = await loadTemplate("Comment.html", {
avatar: "https://loremflickr.com/640/480/people",
username: "Alice",
content: "Hello World!",
date: "January 1, 2023"
});
commentsDiv.appendChild(commentHTML.body.firstChild);
The core implementation of the template engine relies on the loadTemplate function. As seen above, the function takes in the path to the HTMl template we created and an object that has matching keys and desired values to the placeholders we laid out in the template. loadTemplate outputs a HTMl object that we can load onto our website using DOM manipulation.
async function loadTemplate(template, params) {
const html = await fetch(template)
.then(response => response.text())
.then(html => {
let names = Object.keys(params);
let vals = Object.values(params);
return new Function(...names, `return \`${html}\`;`)(...vals);
const parser = new DOMParser();
return parser.parseFromString(html, 'text/html');
}
The first part of the function converts the HTML template into a string then replaces the placeholders with the matching key-value pair given as params. Once this is done, the function converts the string back to a HTML object and returns it to be used.
Authentication
The next hurdle we had to overcome without help from a framework was authentication. Our website had user accounts with sensitive passwords that need to be protected. To accomplish this we store the users’ encrypted passwords in our database when their accounts are created. This is done with a salted hash using bcrypt. When a user is logged in, we hash their inputted password and check it against the corresponding encrypted passwords in our database. If the user is verified then they are logged in with a persisting user session.
A user’s login session is managed by a JSON Web Token that is generated when they successfully log in. This JWT is stored in the browser’s Cookies with the “httpOnly” tag. The reason for this is to reduce the risk from XSS attacks. It should be noted that this is not a fullproof solution against all attacks but is viable enough for the scope of this project. The JWT is viable for 6 hours upon its creation and is removed upon logging out. Once the JWT is unusable, the user must login again to continue their session.
The Canvas
The canvas page is the keystone page for this website. Each project has a canvas room where collaborators of the project can join to share ideas in real time. The key features for this page is the digital drawing canvas and the chat. This is accomplished with the use of socket.io.
The drawing canvas has two main tools which are the brush and eraser. There are buttons to select which tools to use and to adjust their sizes. For the brush there is also the ability to change it to any desired RGB color.
The chat can be toggled on the right side of the canvas. The special feature we included for this chat is the ability to send LaTeX equations. Users can send any rendered LaTeX equations by surrounding LaTeX code with $ (inline) or $$ (block). This is done with the KaTeX API.
Conclusion
This assignment gave us an opportunity to learn how to develop a website from start to finish in a team environment. Some of the things that we learned include: routing, API endpoints, and deployment. Some technologies we learned include: socket.io and bootstrap.
One of the major difficulties we faced was with routing with dynamically generated content. We found this process challenging when we realized our routing implementation was not set up correctly. As a result, we had to reorganize a large part of our code-base and this took a lot of time. If there is something we would like to know prior to starting this project, was that we would prioritize more time in designing the routing of the project. We did this half-way through the project but ideally we want to think about this at the very start. Lastly, another difficulty was with deploying to Heroku. Our heroku code require some changes for it to work: such as the socket.io URL.