Build a Socket.iO Realtime Voting Polling App in Node.js Using Chart.js in Browser Using HTML5 & Javascript
// Import dependencies
const express = require("express");
const app = express();
// If you change this remember to change it on the client side as well
const port = 80;
// Host the front end
app.use(express.static("client"));
// Start the server and initialize socket.io
const server = app.listen(port, () => console.log(`Listening at http://localhost:${port}`));
const io = require("socket.io")(server);
// Initialize candidates
const candidates = {
"0": { votes: 0, label: "JavaScript", color: randomRGB() },
"1": { votes: 0, label: "C#", color: randomRGB() },
"2": { votes: 0, label: "PHP", color: randomRGB() },
"3": { votes: 0, label: "Python", color: randomRGB() },
"4": { votes: 0, label: "Go", color: randomRGB() }
};
// On new client connection
io.on("connection", (socket) => {
io.emit("update", candidates);
// On new vote
socket.on("vote", (index) => {
// Increase the vote at index
if (candidates[index]) {
candidates[index].votes += 1;
}
// Show the candidates in the console for testing
console.log(candidates);
// Tell everybody else about the new vote
io.emit("update", candidates);
});
});
// Generate a random RGB color
function randomRGB() {
const r = () => Math.random() * 256 >> 0;
return `rgb(${r()}, ${r()}, ${r()})`;
}
<!DOCTYPE html>
<html>
<head>
<title>Real Time Polling App using Socket.io</title>
</head>
<body>
<!-- Import dependencies -->
<!-- https://cdnjs.com/libraries/socket.io -->
<!-- https://cdnjs.com/libraries/Chart.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.0.1/socket.io.min.js" integrity="sha512-gVG6WRMUYFaIdoocaxbqd02p3DUbhReTBWc7NTGB96i7vONrr7GuCZJHFFmkXEhpwilIWUnfRIMSlKaApwd/jg==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js" integrity="sha512-d9xgZrVZpmmQlfonhQUvTR7lMPtO7NkZMkA0ABN3PHCbKA5nqylQ/yWlFAyY6hYgdF1Qh6nYiuADWwKB4C2WSw==" crossorigin="anonymous"></script>
<!-- The title -->
<h1 style="text-align: center;">What is the best programming language out of these five?</h1>
<!-- The canvas -->
<canvas id="voteChart" style="height:50vh; width:100vw"></canvas>
<!-- The buttons -->
<button onclick="vote(0)">JavaScript</button>
<button onclick="vote(1)">C#</button>
<button onclick="vote(2)">PHP</button>
<button onclick="vote(3)">Python</button>
<button onclick="vote(4)">Go</button>
<script>
// Initialize the canvas
const ctx = document.getElementById("voteChart").getContext("2d");
// Initialize the chart
const chart = new Chart(ctx, {
type: "bar",
data: {
labels: ["Programming Languages"],
},
options: {
}
});
// Connect to the server it's (Here you want to change the port if you changed it in the server)
const socket = io("localhost:80");
// On new vote update the chart
socket.on("update", (candidates) => {
// Convert the candidates object into an array
candidates = Object.entries(candidates);
// For each candidate
for (const [key, candidate] of candidates) {
// Update the vote if the candidate already exists if not create a new candidate and then update the vote
if(typeof chart.data.datasets[key] == "undefined" && chart.data.datasets.length < candidates.length ) {
chart.data.datasets.push({
backgroundColor: candidate.color,
borderColor: candidate.color,
data: [candidate.votes],
label: candidate.label
});
} else if(typeof chart.data.datasets[key] != "undefined") {
chart.data.datasets[key].data = [candidate.votes];
}
}
// Update the chart
chart.update();
});
// Make a new vote (Remember this is not a safe way to do this)
function vote(index) {
socket.emit("vote", index);
}
</script>
</body>
</html>
// Import dependencies
const express = require("express");
const useragent = require("useragent");
const app = express();
// If you change this remember to change it on the client side as well
const port = 80;
// Host the front end
app.use(express.static("client"));
// Start the server and initialize socket.io
const server = app.listen(port, () => console.log(`Listening at http://localhost:${port}`));
const io = require("socket.io")(server);
// Initialize candidates
const candidates = {
"0": { votes: 0, label: "JavaScript", color: randomRGB() },
"1": { votes: 0, label: "C#", color: randomRGB() },
"2": { votes: 0, label: "PHP", color: randomRGB() },
"3": { votes: 0, label: "Python", color: randomRGB() },
"4": { votes: 0, label: "Go", color: randomRGB() }
};
// All of the users
const users = {};
// Cool down in milliseconds
const coolDown = 6000;
// The magic number
const magicNumber = 25381238823847823427345;
// On new client connection
io.on("connection", (socket) => {
io.emit("update", candidates);
// Parse the user agent string
const userAgent = useragent.parse(socket.handshake.headers["user-agent"]);
// The users IP address
const address = socket.handshake.address;
// Make the handle
const id = hash(userAgent.os.toString() + userAgent.device.toString() + magicNumber);
const handled = hash(id + address + magicNumber);
// On new vote
socket.on("vote", (index) => {
// Check if the user is allowed to vote
if (typeof users[handled] === "undefined" || typeof users[handled] !== "undefined" && users[handled] + coolDown <= Date.now()) {
// Increase the vote at index
if (candidates[index]) {
candidates[index].votes += 1;
}
// Show the candidates in the console for testing
console.log(candidates);
// Tell everybody else about the new vote
io.emit("update", candidates);
// Set the timestamp
users[handled] = Date.now();
}
});
});
// Generate a random RGB color
function randomRGB() {
const r = () => Math.random() * 256 >> 0;
return `rgb(${r()}, ${r()}, ${r()})`;
}
// https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript
function hash(s) {
return s.split("").reduce(function (a, b) { a = ((a << 5) - a) + b.charCodeAt(0); return a & a }, 0);
}