Published
Edited
Jan 26, 2019
1 star
Insert cell
Insert cell
theCanvas = {
const canvas = DOM.canvas(300, 300); // Creates a canvas element
const context = canvas.getContext("2d");
context.fillStyle = "#ffffff";
context.fillRect(0, 0, 300, 300);
let mouseDown = false;
let lastX;
let lastY;
const handleMousedown = () => {
mouseDown = true;
};
const handleMouseup = () => {
mouseDown = false;
[lastX, lastY] = [undefined, undefined];
};
const handleMousemove = (e) => {
const rect = e.target.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;

if (mouseDown) {
[lastX, lastY] = drawLine(e.target, x, y, lastX, lastY);
}
};
// The code below is what makes the canvas "drawable" and gives it a nice black border.
canvas.addEventListener("mousedown", handleMousedown);
canvas.addEventListener("mouseup", handleMouseup);
canvas.addEventListener("mousemove", handleMousemove);
canvas.style.boxShadow = "-1px -1px 0 black, 1px -1px 0 black, -1px 1px 0 black, 1px 1px 0 black";
canvas.style.margin = "20px";
return canvas;
}
Insert cell
drawLine = (canvas, x, y, lastX, lastY) => {
let ctx = canvas.getContext("2d");

ctx.strokeStyle = "#000000";
ctx.lineWidth = 12;
ctx.lineJoin = "round";

ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(x, y);
ctx.closePath();
ctx.stroke();

return [x, y];
}
Insert cell
Insert cell
clearCanvas = {
const clearButton = html `<button>Clear the canvas</button>`;
clearButton.onclick = () => {
theCanvas.getContext("2d").fillRect(0, 0, 300, 300);
};
return clearButton;
}
Insert cell
Insert cell
tf = require('@tensorflow/tfjs');
Insert cell
Insert cell
model = await tf
.loadModel("https://gist.githubusercontent.com/albertowar/d34b5fe1f5b463ddcdc46a14159cf2cd/raw/e8757ba1b4457c25865c56b0016f2d67c4a508a0/model.json");
Insert cell
Insert cell
tensor = preprocessCanvas(theCanvas);
Insert cell
preprocessCanvas = (canvas) => {
// Preprocess image for the network
let tensor = tf
.fromPixels(canvas) // Shape: (300, 300, 3) - RGB image
.resizeNearestNeighbor([28, 28]) // Shape: (28, 28, 3) - RGB image
.mean(2) // Shape: (28, 28) - grayscale
.expandDims(2) // Shape: (28, 28, 1) - network expects 3d values with channels in the last dimension
.expandDims() // Shape: (1, 28, 28, 1) - network makes predictions for "batches" of images
.toFloat(); // Network works with floating points inputs
return tensor.div(255.0); // Normalize [0..255] values into [0..1] range
}
Insert cell
Insert cell
prediction = await model.predict(tensor).data();
Insert cell
Insert cell
result = tf.argMax(prediction).data();
Insert cell
Insert cell
predictedLabel = labels[result];
Insert cell
Insert cell
Insert cell
Insert cell
{
const letters = predictedLabel.toUpperCase().split('').map((letter, i) => {
const rand = Math.floor(Math.random() * Math.floor(colors.length - 1));
const fill = colors[rand];
return `<tspan fill="${fill}">${letter}</tspan>`;
});
return svg`<svg id="prediction" width="975" height="180">
<text x="15"
y="90"
font-size="72px"
font-family="Righteous"
lengthAdjust="spacing"
textLength="500"
stroke="#151515"
stroke-width="5">${letters}</text>
</svg>`;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more