Script
Script
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
<title>Cricket run counter</title>
<!-- <link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/5/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
crossorigin="anonymous"> -->
<!-- CSS only -->
<script
src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.2/mqttws31.min.js"
type="text/javascript"></script>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-
+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x"
crossorigin="anonymous">
<link rel="stylesheet" href="main.css">
<body style="background-color:#e5f3ff;">
<div class="container">
<!-- This is the scores on the topmost part of the screen -->
<div class="col-left-custom">
<h6 style="text-align:center;">
<!-- <span style="vertical-align:0.7em; font-size: small;">Score: </span>
-->
<span contentEditable="false" id="run" style="font-size:30vw; line-height:
80%;">0</span>
<span contentEditable="false" style="font-size:25vw; line-height:
80%;">/</span>
<span contentEditable="false" id="wickets" style="font-size:30vw; line-
height: 80%;">0</span>
<span id="over-ball" style="font-size: 10vw; line-height: 200%">0</span>
<center><h6 style="color: red; display: none;" id="no-ball-warning">No
ball: Tap the runs scored in no ball.</h6></center>
</h6>
</div>
<!-- END: This is the scores on the topmost part of the screen -->
<!-- These are the action buttons and runboard -->
<div class="col-right-custom">
<div class="position-relative m-4">
<div class="progress" style="height: 1px;">
<div class="progress-bar" role="progressbar" style="width: 0%;"></div>
</div>
<button type="button"
class="position-absolute top-0 start-0 translate-middle btn btn-sm btn-
primary rounded-pill over-ball-style"
id="ball_no_1"></button>
<button type="button"
class="position-absolute top-0 start-50 translate-middle btn btn-sm btn-
light rounded-pill over-ball-style"
id="ball_no_2"></button>
<button type="button"
class="position-absolute top-0 start-100 translate-middle btn btn-sm btn-
light rounded-pill over-ball-style"
id="ball_no_3"></button>
</div>
<div class="position-relative m-4 my-5">
<div class="progress" style="height: 1px;">
<div class="progress-bar" role="progressbar" style="width: 0%;"></div>
</div>
<button type="button"
class="position-absolute top-0 start-0 translate-middle btn btn-sm btn-
light rounded-pill over-ball-style"
id="ball_no_4"></button>
<button type="button"
class="position-absolute top-0 start-50 translate-middle btn btn-sm btn-
light rounded-pill over-ball-style"
id="ball_no_5"></button>
<button type="button"
class="position-absolute top-0 start-100 translate-middle btn btn-sm btn-
light rounded-pill over-ball-style"
id="ball_no_6"></button>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-
dismiss="modal">Close</button>
<button type="button" class="btn btn-primary " onclick="setTarget()"
data-dismiss="modal">Set
Target</button>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer" id="shareModalFooter">
</div>
</div>
</div>
</div>
</div>
<div id="messages"></div>
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
integrity="sha384-
J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
crossorigin="anonymous"></script>
<script
src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
integrity="sha384-
Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
crossorigin="anonymous"></script>
<script
src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity="sha384-
wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
crossorigin="anonymous"></script>
<script src="main_mqtt.js"></script>
<script src="main.js"></script>
</body>
</html>
main.css
html,
body,
.container {
margin: 0px;
max-width: 100%;
}
.col-left-custom,
.col-left-custom {
width: 100%;
}
.over-ball-style {
width: 2rem;
height: 2rem;
}
.center {
margin: auto;
width: 100%;
border: 3px solid green;
padding: 10px;
}
.btn-custom {
display: inline-block;
width: 100%;
}
.btn-custom-lg {
height: 4.5em;
}
.btn-custom-sm {
height: 3em;
}
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td,
th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
.material-symbols-outlined {
font-variation-settings: "FILL" 0, "wght" 400, "GRAD" 200, "opsz" 24;
}
main.js
var scoreboard = [[], [0]]; //scoreboard[<over_no>][0] counts wide runs
var ball_no = 1; // Ball number will start from 1
var over_no = 1; // Over number will start from 1
var runs = 0;
var edited = [];
var isNoBall = false;
var isTargetMode = false;
var targetRuns = -1; // total runs scored by other team
var targetOvers = -1; //total overs
var isShareMode = false;
$(document).ready(function () {
$("#run_dot").on("click", function (event) {
play_ball("D", 0);
});
$("#run_1").on("click", function (event) {
play_ball(1);
});
$("#run_2").on("click", function (event) {
play_ball(2);
});
$("#run_3").on("click", function (event) {
play_ball(3);
});
$("#run_wide").on("click", function (event) {
play_ball("+", 0);
});
$("#run_no_ball").on("click", function (event) {
play_ball("NB", 0);
});
$("#run_4").on("click", function (event) {
play_ball(4);
});
$("#run_6").on("click", function (event) {
play_ball(6);
});
$("#run_W").on("click", function (event) {
play_ball("W", 0);
});
$("#scoreboard-btn").on("click", function (event) {
update_scoreboard();
});
init();
});
function init() {
const urlParams = new URLSearchParams(window.location.search);
console.log("urlParams.get()");
console.log(urlParams.get("debug"));
if (urlParams.get("debug") == null || urlParams.get("debug") != "true")
$("#messages").hide();
// const queryString = window.location.search;
// const urlParams = new URLSearchParams(queryString);
// console.log(urlParams.get("matchCode"));
// console.log(document.location.origin);
}
function shareModeStart() {
isShareMode = true;
startConnect();
}
if (isNoBall) {
scoreboard[over_no][0] += run == "D" ? 0 : run;
// isNoBall = false;
noBall(false);
} else {
scoreboard[over_no][ball_no] = run;
// console.log(scoreboard[over_no]);
// console.log(scoreboard);
update_runboard();
ball_no++;
if (ball_no >= 7) {
ball_no = 1;
over_no++;
scoreboard[over_no] = [];
scoreboard[over_no][0] = 0; //Wide bowls counter
}
}
update_score();
update_scoreboard();
}
function update_runboard() {
// Updates the runboard when the function is called
for (i = 1; i < 7; i++) {
let score_und = (_score_und) => (_score_und == undefined ? "" :
_score_und);
updateHtml("#ball_no_" + i.toString(), score_und(scoreboard[over_no]
[i]));
}
if (ball_no != 1) {
$("#ball_no_" + ball_no.toString()).removeClass("btn-light");
$("#ball_no_" + ball_no.toString()).addClass("btn-primary");
} else {
for (i = 2; i <= 6; i++) {
$("#ball_no_" + i.toString()).removeClass("btn-primary");
$("#ball_no_" + i.toString()).addClass("btn-light");
}
}
updateHtml(
"#over-ball",
(ball_no == 6 ? over_no : over_no - 1).toString() +
"." +
(ball_no == 6 ? 0 : ball_no).toString()
);
}
function change_score() {
let over = parseInt($("#change_over").val());
let ball = parseInt($("#change_ball").val());
let run = parseInt($("#change_run").val());
edited.push([over, ball, scoreboard[over][ball], run]);
scoreboard[over][ball] = run;
update_score();
update_scoreboard();
updateHtml("#run", runs);
let edited_scores = "Edited scores:<br>";
for (i = 0; i < edited.length; i++) {
edited_scores +=
"(" +
edited[i][0].toString() +
"." +
edited[i][1].toString() +
") = " +
edited[i][2].toString() +
" -> " +
edited[i][3].toString();
edited_scores += "<br>";
}
// }
updateHtml("#edited-scores", edited_scores);
}
function update_scoreboard() {
// Updates the table in the modal which appears when the scoreboard button is
pressed.
var table = "";
for (i = 1; i <= over_no; i++) {
table = table + "<tr>";
table += "<td>" + i.toString() + "</td>";
table +=
"<td>" +
scoreboard[i].slice(1, 7).join(" - ") +
" (" +
scoreboard[i][0].toString() +
")" +
"</td>";
table = table + "</tr>";
}
updateHtml(
"#scoreboard",
"<tr><th>Over</th><th>Score (Extras)</th></tr>" + table
);
}
function update_score() {
let score = 0;
let wickets = 0;
function back_button() {
if (over_no == 1 && ball_no == 1) return;
ball_no--;
if (ball_no == 0) {
ball_no = 6;
over_no--;
}
scoreboard[over_no][ball_no] = undefined;
update_score();
update_scoreboard();
update_runboard();
updateHtml(
"#over-ball",
(over_no - 1).toString() + "." + (ball_no - 1).toString()
);
}
function noBall(is_NoBall) {
isNoBall = is_NoBall;
var run_no_ball = $("#run_no_ball");
if (is_NoBall) {
$("#no-ball-warning").show();
$("#run_wide").prop("disabled", true);
$("#run_no_ball").prop("disabled", true);
$("#run_W").prop("disabled", true);
run_no_ball.css("backgroundColor", "#0D6EFD");
run_no_ball.css("color", "#ffffff");
} else {
$("#no-ball-warning").hide();
$("#run_wide").prop("disabled", false);
$("#run_no_ball").prop("disabled", false);
$("#run_W").prop("disabled", false);
run_no_ball.css("backgroundColor", "#e5f3ff");
run_no_ball.css("color", "#0D6EFD");
}
}
function updateTarget() {
if (!isTargetMode) return;
updateHtml("#targetRunsRequired", targetRuns - runs);
let ballsLeft = targetOvers * 6 - ((over_no - 1) * 6 + ball_no - 1);
updateHtml("#targetOversLeft", ballsLeft);
let closeButton =
' <button type="button" class="btn-close"
onClick="setTarget(false)"></button>';
if (ballsLeft == 0) {
if (targetRuns < runs) {
updateHtml(
"#targetBody",
"Hurray! The batting team has Won!!" + closeButton
);
} else if (targetRuns - 1 == runs) {
updateHtml("#targetBody", "Match Over! It's a tie." +
closeButton);
} else {
updateHtml(
"#targetBody",
"Hurray! The bowling team has Won!!" + closeButton
);
}
$("#targetModeButton").show();
}
if (targetRuns <= runs) {
updateHtml(
"#targetBody",
"Hurray! The batting team has Won!!" + closeButton
);
$("#targetModeButton").show();
}
}
function sendInitVariables() {
let vars = {
"#ball_no_1": $("#ball_no_1").html(),
"#ball_no_2": $("#ball_no_2").html(),
"#ball_no_3": $("#ball_no_3").html(),
"#ball_no_4": $("#ball_no_4").html(),
"#ball_no_5": $("#ball_no_5").html(),
"#ball_no_6": $("#ball_no_6").html(),
"#over-ball": $("#over-ball").html(),
"#run": $("#run").html(),
"#edited-scores": $("#edited-scores").html(),
"#scoreboard": $("#scoreboard").html(),
"#wickets": $("#wickets").html(),
"#targetRunsRequired": $("#targetRunsRequired").html(),
"#targetBody": $("#targetBody").html(),
};
publishMessage(
JSON.stringify({
init: vars,
isTargetMode: isTargetMode,
})
);
}
main_mqtt.js
var topic = -1;
let isStartConnectDone = false;
function startConnect(_topic) {
clientID = "clientID - " + parseInt(Math.random() * 100);
host = "test.mosquitto.org";
port = 8080;
topic = _topic ?? "" + parseInt(Math.random() * 1000000);
let seralizedLink =
document.location.origin + "/watch.html?matchCode=" + topic;
seralizedLink = encodeURI(seralizedLink);
document.getElementById("shareModalBody").innerHTML =
"<h4>Share this code:" +
' <span class="badge bg-secondary">' +
topic +
"</span> " +
'<button class="btn btn-primary"
onclick="navigator.clipboard.writeText(\'' +
topic +
'\')" data-dismiss="modal">' +
'<span class="material-symbols-outlined">content_copy</span>';
("</span></h4>");
document.getElementById("shareModalFooter").innerHTML =
'<button type="button" class="btn btn-default" data-
dismiss="modal">Close</button>' +
'<button type="button" class="btn btn-default"
onclick="navigator.clipboard.writeText(\'' +
seralizedLink +
'\')" data-dismiss="modal">Copy link</button>' +
'<a href="whatsapp://send?text=Follow the match score at: ' +
document.location.origin +
"/watch.html?matchCode=" +
topic +
'" data-action="share/whatsapp/share">Share via Whatsapp</a>';
document.getElementById("messages").innerHTML +=
"<span> Connecting to " + host + "on port " + port + "</span><br>";
document.getElementById("messages").innerHTML +=
"<span> Using the client Id " + clientID + " </span><br>";
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
client.connect({
onSuccess: onConnect,
// userName: userId,
// passwordId: passwordId
});
isStartConnectDone = true;
}
function onConnect() {
document.getElementById("messages").innerHTML +=
"<span> Subscribing to topic " + topic + "</span><br>";
function onConnectionLost(responseObject) {
document.getElementById("messages").innerHTML +=
"<span> ERROR: Connection is lost.</span><br>";
if (responseObject != 0) {
document.getElementById("messages").innerHTML +=
"<span> ERROR:" + responseObject.errorMessage + "</span><br>";
}
}
function onMessageArrived(message) {
console.log("OnMessageArrived: " + message.payloadString);
document.getElementById("messages").innerHTML +=
"<span> Topic:" +
message.destinationName +
"| Message : " +
message.payloadString +
"</span><br>";
payload = JSON.parse(message.payloadString);
if (payload.init != undefined && payload.init == "true") {
sendInitVariables();
}
}
// function startDisconnect() {
// client.disconnect();
// document.getElementById("messages").innerHTML +=
// "<span> Disconnected. </span><br>";
// }
function publishMessage(msg) {
if (!isStartConnectDone) return;
// msg = document.getElementById("Message").value;
// topic = document.getElementById("topic_p").value;
client.send(Message);
document.getElementById("messages").innerHTML +=
"<span> Message to topic " + topic + " is sent </span><br>";
}
watch.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
<title>Cricket run counter</title>
<!-- <link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/5/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
crossorigin="anonymous"> -->
<!-- CSS only -->
<script
src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.2/mqttws31.min.js"
type="text/javascript"></script>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-
+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x"
crossorigin="anonymous">
<link rel="stylesheet" href="main.css">
</head>
<body style="background-color:#e5f3ff;">
<div class="container">
<div class="alert alert-primary text-center" role="alert" style="display: none;
transition: height 1400ms;" id="alert">
</div>
<!-- This is the scores on the topmost part of the screen -->
<div class="col-left-custom">
<h6 style="text-align:center;">
<!-- <span style="vertical-align:0.7em; font-size: small;">Score: </span>
-->
<span contentEditable="false" id="run" style="font-size:30vw; line-height:
80%;">0</span>
<span contentEditable="false" style="font-size:25vw; line-height:
80%;">/</span>
<span contentEditable="false" id="wickets" style="font-size:30vw; line-
height: 80%;">0</span>
<span id="over-ball" style="font-size: 10vw; line-height: 200%">0</span>
</h6>
</div>
<!-- END: This is the scores on the topmost part of the screen -->
</div>
<div class="modal-footer" id="shareModalFooter">
<button type="button" class="btn btn-default" data-
dismiss="modal"onclick="getMatchCodeNConnect()">Go</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="messages"></div>
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
integrity="sha384-
J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
crossorigin="anonymous"></script>
<script
src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
integrity="sha384-
Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
crossorigin="anonymous"></script>
<script
src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity="sha384-
wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
crossorigin="anonymous"></script>
<!-- <script src="watch_mqtt.js"></script> -->
<script src="watch.js"></script>
</body>
</html>
watch.js
var scoreboard = [[], [0]]; //scoreboard[<over_no>][0] counts wide runs
var ball_no = 1; // Ball number will start from 1
var over_no = 1; // Over number will start from 1
var runs = 0;
var edited = [];
var isNoBall = false;
var isTargetMode = false;
var targetRuns = -1; // total runs scored by other team
var targetOvers = -1; //total overs
$(document).ready(function () {
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get("matchCode") != null) {
console.log(urlParams.get("matchCode"));
startConnect(urlParams.get("matchCode")); //TODO
} else {
// $('#matchCodeInput').modal('show');
let myModal = new bootstrap.Modal(
document.getElementById("shareModal"),
{}
);
myModal.show();
}
console.log(document.location.origin);
function getMatchCodeNConnect() {
let matchCode = $("#matchCodeInput").val();
startConnect(matchCode);
}
function startConnect(_topic) {
clientID = "clientID - " + parseInt(Math.random() * 100);
host = "test.mosquitto.org";
port = 8080;
topic = _topic ?? "" + parseInt(Math.random() * 1000000);
document.getElementById("messages").innerHTML +=
"<span> Connecting to " + host + "on port " + port + "</span><br>";
document.getElementById("messages").innerHTML +=
"<span> Using the client Id " + clientID + " </span><br>";
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
client.connect({
onSuccess: onConnect,
// userName: userId,
// passwordId: passwordId
});
isStartConnectDone = true;
console.log("start connect done!");
}
function onConnect() {
document.getElementById("messages").innerHTML +=
"<span> Subscribing to topic " + topic + "</span><br>";
client.subscribe("matchCodeWatch" + topic);
publishMessage(JSON.stringify({ init: "true" }));
console.log("onConnect called");
}
function onConnectionLost(responseObject) {
document.getElementById("messages").innerHTML +=
"<span> ERROR: Connection is lost.</span><br>";
if (responseObject != 0) {
document.getElementById("messages").innerHTML +=
"<span> ERROR:" + responseObject.errorMessage + "</span><br>";
}
}
function onMessageArrived(message) {
console.log("OnMessageArrived: " + message.payloadString);
document.getElementById("messages").innerHTML +=
"<span> Topic:" +
message.destinationName +
"| Message : " +
message.payloadString +
"</span><br>";
// msg = document.getElementById("Message").value;
// topic = document.getElementById("topic_p").value;
client.send(Message);
document.getElementById("messages").innerHTML +=
"<span> Message to topic " + topic + " is sent </span><br>";
}
function initHtml(payload) {
// console.log(JSON.parse(initVars));
for (let keys in payload.init) {
$(keys).html(payload.init[keys]);
}
setTargetMode(payload.isTargetMode);
}
function setTargetMode(isTargetMode) {
isTargetMode ??= false;
if (isTargetMode) $("#targetBody").show();
else $("#targetBody").hide();
}
function showConnected() {
console.log("Connected successfully!");
$("#alert").html("Connected successfully!");
$("#alert").show();
setTimeout(function () {
$("#alert").hide();
}, 4000);
}