...
 
Commits (5)
......@@ -6,42 +6,44 @@ body {
.content {
display: grid;
grid-template-columns: 0.5fr 0.5fr 0.5fr 0.5fr 1fr 1fr;
grid-template-rows: 1fr 3fr 1fr;
grid-template-columns: 2fr 1fr 1fr;
grid-template-rows: 1fr 2fr 1fr;
grid-gap: 1%;
align-items: center;
}
#operazione {
font-size: 200%;
grid-column: 1 / 5;
grid-column: 1 / 2;
grid-row: 1 / 4;
}
#label_d {
grid-column: 5;
grid-column: 2;
grid-row: 1;
}
#decine {
border: 3px solid magenta;
grid-column: 5;
grid-column: 2;
grid-row: 2;
touch-action: none;
}
#label_u {
grid-column: 6;
grid-column: 3;
grid-row: 1;
}
#unita {
border: 3px solid cyan;
grid-column: 6;
grid-column: 3;
grid-row: 2;
touch-action: none;
}
#interazione {
grid-column: 1 / 7;
grid-column: 1 / 4;
grid-row: 3;
}
......@@ -49,6 +51,18 @@ body {
font-size: 150%;
}
.check {
background-color: lightblue;
}
.ok {
background-color: lightgreen;
}
.ko {
background-color: red;
}
.footnote {
margin-top: 50px;
font-size: 30%;
......
......@@ -4,6 +4,7 @@
<title>Conticini</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="conticini.css" type="text/css" media="screen" />
<link rel="icon" href="conticini.png" type="image/png" />
</head>
<body onload="randomize();">
......@@ -24,11 +25,12 @@
<canvas id="cifra_u"></canvas>
</div>
<div id="interazione">
<input type="button" id="pulsante" value="CONTROLLA" />
<input type="button" id="pulsante"/>
</div>
</div>
<canvas id="canvas_tmp" width="28" height="28" style="display: none;"></canvas>
<script type="text/javascript" src="globals.js"></script>
<script type="text/javascript" src="drawing.js"></script>
<script type="text/javascript" src="randomize.js"></script>
<!-- Load ONNX.js -->
......
......@@ -2,21 +2,15 @@
// Basic idea from https://gist.github.com/peshoicov/ab3286875d980948ad3f5f434fec37a9
// and http://bencentra.com/code/2014/12/05/html5-canvas-touch-events.html
// HTML elements
const CONTICINO = document.getElementById('operazione');
const CIFRA_D = document.getElementById('cifra_d');
const CIFRA_U = document.getElementById('cifra_u');
// some variables we'll need ..
var drawing = null;
var mousePos = {x:0, y:0};
var lastPos = mousePos;
var isMobile = ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch;
const canvasDim = 0.45*CONTICINO.clientWidth;
const canvasDim = 0.45*Conticini.CONTICINO.clientWidth;
setupCanvas(CIFRA_D);
setupCanvas(CIFRA_U);
setupCanvas(Conticini.CIFRA_D);
setupCanvas(Conticini.CIFRA_U);
function setupCanvas(canvas){
// Setup canvas ..
......
// HTML elements
var Conticini = {
CONTICINO: document.getElementById('operazione'),
CIFRA_D: document.getElementById('cifra_d'),
CIFRA_U: document.getElementById('cifra_u'),
CANVAS_TMP: document.getElementById('canvas_tmp'),
OPERANDO_SX: document.getElementById('operando_sx'),
OPERANDO_DX: document.getElementById('operando_dx'),
OPERATORE: document.getElementById('operatore'),
PULSANTE: document.getElementById('pulsante'),
// Feel free to configure these
MIN_OPERANDO: 0,
MAX_OPERANDO: 9,
MIN_EXPECTED: 0,
MAX_EXPECTED: 20,
OPS: ['+', '-'],
OK_TIMEOUT: 5000,
KO_TIMEOUT: 3000,
MSG_CHECK: "CONTROLLA",
MSG_OK: "BENISSIMO!",
MSG_KO: "HAI SCRITTO MALE, RIPROVA!",
// expected result
expected: null,
};
// Copyright (C) 2020 by Mattia Monga <[email protected]>
// Code that consume ONNX.js mainly from https://github.com/microsoft/onnxjs-demo
// HTML elements
const CANVAS_TMP = document.getElementById('canvas_tmp');
async function getNumber(canvas) {
async function getNumber(canvas, tmp) {
const myOnnxSession = new onnx.InferenceSession({ backendHint: "webgl" });
// load the ONNX model file
await myOnnxSession.loadModel("./model.onnx");
// Preprocess the image data to match input dimension requirement, which is 1*1*28*28.
const width = 28;
const height = 28;
const preprocessedData = preprocess(canvas, width, height);
const preprocessedData = preprocess(canvas, tmp, width, height);
const inputTensor = new onnx.Tensor(preprocessedData, 'float32', [1, 1, width, height]);
const outputMap = await myOnnxSession.run([inputTensor]);
......@@ -24,14 +21,14 @@ async function getNumber(canvas) {
function softmax(arr) {
const C = Math.max(...arr);
const d = arr.map((y) => Math.exp(y - C)).reduce((a, b) => a + b);
return arr.map((value, index) => {
return arr.map((value, index) => {
return Math.exp(value - C) / d;
});
}
function preprocess(canvas, width, height) {
function preprocess(canvas, tmp, width, height) {
const ctx = canvas.getContext('2d');
const ctxScaled = CANVAS_TMP.getContext('2d');
const ctxScaled = tmp.getContext('2d');
ctxScaled.save();
ctxScaled.scale(width / ctx.canvas.width, height / ctx.canvas.height);
......
// Copyright (C) 2020 by Mattia Monga <[email protected]>
const MIN_OPERANDO = 0;
const MAX_OPERANDO = 9;
const MIN_EXPECTED = 0;
const MAX_EXPECTED = 20;
const OPS = ['+', '-'];
const OPERANDO_SX = document.getElementById('operando_sx');
const OPERANDO_DX = document.getElementById('operando_dx');
const OPERATORE = document.getElementById('operatore');
const PULSANTE = document.getElementById('pulsante');
var g_operando_sx, g_operando_dx, g_operatore, g_expected;
function randomize() {
var op_sx, op, op_dx;
do {
g_operando_sx = Math.floor(MIN_OPERANDO + Math.random()*(MAX_OPERANDO - MIN_OPERANDO + 1));
g_operando_dx = Math.floor(MIN_OPERANDO + Math.random()*(MAX_OPERANDO - MIN_OPERANDO + 1));
g_operatore = OPS[Math.floor(Math.random()*OPS.length)];
g_expected = eval(g_operando_sx + g_operatore + g_operando_dx);
} while (g_expected < MIN_EXPECTED || g_expected > MAX_EXPECTED);
OPERANDO_SX.innerHTML = "" + g_operando_sx;
OPERANDO_DX.innerHTML = "" + g_operando_dx;
OPERATORE.innerHTML = g_operatore;
reset();
op_sx = Math.floor(Conticini.MIN_OPERANDO
+ Math.random()*(Conticini.MAX_OPERANDO - Conticini.MIN_OPERANDO + 1));
op_dx = Math.floor(Conticini.MIN_OPERANDO
+ Math.random()*(Conticini.MAX_OPERANDO - Conticini.MIN_OPERANDO + 1));
op = Conticini.OPS[Math.floor(Math.random()*Conticini.OPS.length)];
Conticini.expected = eval(op_sx + op + op_dx);
} while (Conticini.expected < Conticini.MIN_EXPECTED || Conticini.expected > Conticini.MAX_EXPECTED);
Conticini.OPERANDO_SX.innerHTML = "" + op_sx;
Conticini.OPERANDO_DX.innerHTML = "" + op_dx;
Conticini.OPERATORE.innerHTML = op;
reset_canvases();
}
function reset() {
const ctx_u = CIFRA_U.getContext('2d');
const ctx_d = CIFRA_D.getContext('2d');
function reset_canvases() {
const ctx_u = Conticini.CIFRA_U.getContext('2d');
const ctx_d = Conticini.CIFRA_D.getContext('2d');
ctx_u.clearRect(0, 0, ctx_u.canvas.width, ctx_u.canvas.height);
ctx_u.beginPath();
ctx_d.clearRect(0, 0, ctx_d.canvas.width, ctx_d.canvas.height);
ctx_d.beginPath();
PULSANTE.value = "CONTROLLA";
PULSANTE.style.background = 'lightblue';
PULSANTE.onclick = controlla;
Conticini.PULSANTE.value = Conticini.MSG_CHECK;
Conticini.PULSANTE.className = 'check';
Conticini.PULSANTE.onclick = check_result;
}
function ko_msg(timeout){
PULSANTE.value = "HAI SCRITTO MALE, RIPROVA!";
PULSANTE.style.background = 'red';
window.setTimeout(reset, timeout);
function ko_msg(timeout) {
Conticini.PULSANTE.value = Conticini.MSG_KO;
Conticini.PULSANTE.className = 'ko';
window.setTimeout(reset_canvases, timeout);
}
function ok_msg(timeout){
PULSANTE.value = "Benissimo!";
PULSANTE.style.background = 'lightgreen';
function ok_msg(timeout) {
Conticini.PULSANTE.value = Conticini.MSG_OK;
Conticini.PULSANTE.className = 'ok';
window.setTimeout(randomize, timeout);
}
async function controlla(){
const u = await getNumber(CIFRA_U);
async function check_result() {
const u = await getNumber(Conticini.CIFRA_U, Conticini.CANVAS_TMP);
if (u === -1) {
ko_msg(3000);
ko_msg(Conticini.KO_TIMEOUT);
return;
}
const d = await getNumber(CIFRA_D);
if ((d === -1 && u === g_expected) || (d > -1 && 10*d + u === g_expected)) {
ok_msg(5000);
const d = await getNumber(Conticini.CIFRA_D, Conticini.CANVAS_TMP);
if ((d === -1 && u === Conticini.expected) || (d > -1 && 10*d + u === Conticini.expected)) {
ok_msg(Conticini.OK_TIMEOUT);
return;
}
ko_msg(3000);
ko_msg(Conticini.KO_TIMEOUT);
}