commit fc1ff1b47b245f3f3f5a761ecd01d8d829158e85 Author: h7x4 Date: Fri Nov 20 20:57:24 2020 +0100 initial commit diff --git a/index.html b/index.html new file mode 100644 index 0000000..99c08d0 --- /dev/null +++ b/index.html @@ -0,0 +1,15 @@ + + + + + + Kanji Recognition + + + + + +
None
+ + + \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..df740d2 --- /dev/null +++ b/script.js @@ -0,0 +1,160 @@ +const responseDiv = document.getElementById("response"); +const clearButton = document.getElementById("clear"); +const canvas = document.getElementById("canvas"); +const ctx = canvas.getContext('2d'); + +/* -------------------------------------------------------------------------- */ +/* API */ +/* -------------------------------------------------------------------------- */ + +const MAX_RESULTS = 10; +const API = 'https://inputtools.google.com/request?itc=ja-t-i0-handwrit&app=translate'; +const DEVICE = navigator.userAgent + +const generateRequestData = strokes => ({ + app_version: 0.4, + api_level: '537.36', + device: DEVICE, + input_type: 0, + options: 'enable_pre_space', + requests: [ + { + writing_guide: { + writing_area_width: canvas.width, + writing_area_height: canvas.height + }, + pre_context: '', + max_num_results: MAX_RESULTS, + max_completions: 0, + language: 'ja', + ink: strokes + } + ] +}); + +const sendKanjiRequest = async (strokes) => fetch(API, { + headers: { "content-type": "application/json; charset=UTF-8" }, + body: JSON.stringify(generateRequestData(strokes)), + method: "POST" +}) + .then(data => data.json()) + .then(res => { + if (res[0] != "SUCCESS") throw Error(res[0]); + responseDiv.innerText = res[1][0][1].join(', '); + }) + .catch(err => console.error(err)); + +/* -------------------------------------------------------------------------- */ +/* CANVAS */ +/* -------------------------------------------------------------------------- */ + +const MILLISECONDS_PER_POINT = 20; + +canvas.height = 500; +canvas.width = 500; + +ctx.strokeStyle = 'black'; +ctx.lineWidth = 2; +ctx.lineCap = 'round'; +ctx.lineJoin = 'round'; + +let strokes = []; + +let newStroke = {}; +let mouseDown = false; +let drawingTimeout = -1; +let timerStart = 0; +let x = 0; +let y = 0; + +/** Clear/initialize the newStroke variable after adding the current to globalStrokes */ +genNewStroke = () => { + newStroke = { + 'xs': [], + 'ys': [], + 'times': [], + }; +} + +genNewStroke(); + +const addPointToNewStroke = (x, y) => { + newStroke.xs.push(x); + newStroke.ys.push(y); + newStroke.times.push(Date.now() - timerStart); +} + +const drawLine = (dx, dy) => { + ctx.moveTo(x, y); + ctx.lineTo(dx, dy); + ctx.stroke(); +} + +updateStroke = (newX, newY) => { + drawLine(newX, newY); + addPointToNewStroke(newX, newY); + x = newX; + y = newY; + drawingTimeout = -1; +} + +const initStroke = (initX, initY) => { + genNewStroke(); + timerStart = Date.now(); + x = initX; + y = initY; + mouseDown = true; + ctx.beginPath(); +} + +const updateStrokeIfPrevLineIsDone = (newX, newY) => { + if (mouseDown === true && drawingTimeout === -1) + drawingTimeout = setTimeout( + () => updateStroke(newX, newY), + MILLISECONDS_PER_POINT + ); +} + +const endStroke = () => { + if (!(drawingTimeout === -1)) { + clearTimeout(drawingTimeout); + drawingTimeout = -1; + } + mouseDown = false; + ctx.closePath(); + strokes.push([newStroke.xs, newStroke.ys, newStroke.times]); + sendKanjiRequest(strokes); +} + +const clearBoard = () => { + strokes = []; + ctx.clearRect(0, 0, canvas.width, canvas.height); + responseDiv.innerHTML = 'None'; +} + +canvas.onmousedown = event => initStroke(event.offsetX, event.offsetY); +canvas.onmousemove = event => updateStrokeIfPrevLineIsDone(event.offsetX, event.offsetY); +canvas.onmouseup = () => endStroke(); + +const getOffset = (x, y) => { +const canvasRect = canvas.getBoundingClientRect(); +return [x - canvasRect.left, y - canvasRect.top]; +} + +canvas.ontouchstart = event => { + event.preventDefault(); + ({clientX, clientY} = event.changedTouches[0]); + [x, y] = getOffset(clientX, clientY); + initStroke(x, y); +} + +canvas.ontouchmove = event => { + event.preventDefault(); + ({clientX, clientY} = event.changedTouches[0]); + [x, y] = getOffset(clientX, clientY); + updateStrokeIfPrevLineIsDone(x, y); +} + +canvas.ontouchend = () => endStroke(); + +clearButton.onclick = () => clearBoard(); \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..8f5cf26 --- /dev/null +++ b/style.css @@ -0,0 +1,20 @@ +body { + text-align: center; +} + +#canvas { + border: solid black 2px; + border-radius: 5px; + background-color: wheat; + margin: 2em; +} + +#response { + font-size: 2em; + margin-bottom: 1em; +} + +#clear { + font-size: 1.4em; + padding: 0.5em 1em; +} \ No newline at end of file