Skip to content

Commit

Permalink
hand written component completed
Browse files Browse the repository at this point in the history
  • Loading branch information
saliherdemk committed Oct 16, 2024
1 parent 6ed1061 commit 21346b0
Show file tree
Hide file tree
Showing 12 changed files with 257 additions and 93 deletions.
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ <h3>Grada</h3>
<script src="js/Draw/Layer/OutputLayer.js"></script>

<script src="js/HandWritten/DigitInputGrid.js"></script>
<script src="js/HandWritten/DigitComponent.js"></script>

<script src="js/Draw/NeuronView.js"></script>

Expand Down
5 changes: 5 additions & 0 deletions js/Draw/Layer/BaseLayers/Component.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ class Component extends FunctionalLayerView {
this.doubleClicked();
}

updateButtons(hide) {
const button = this.removeButton;
hide ? button.hide() : button.visible();
}

replace(layer) {
const isShrank = layer.isShrank();
const neuronsNum = isShrank
Expand Down
5 changes: 0 additions & 5 deletions js/Draw/Layer/BaseLayers/IOLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@ class IOLayer extends Component {
this.recordNum = this.getDataset().shapeY[0];
}

updateButtons(hide) {
const button = this.removeButton;
hide ? button.hide() : button.visible();
}

initialize() {
this.updateShownBatch();
this.adjustNeurons();
Expand Down
14 changes: 5 additions & 9 deletions js/Draw/MLP/MLPView.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,15 +324,11 @@ class MlpView extends Playable {
super.handlePressed();
}

handleKeyPressed() {
iManager.isHovered(this) && this.resetCoordinates();
}

handleReleased() {
this.getLayers().forEach((layer) => {
layer.released();
});
this.released();
handleKeyPressed(k) {
if (iManager.isHovered(this)) {
k == "e" && this.resetCoordinates();
}
this.getInput()?.handleKeyPressed(k);
}

handleDoubleClicked() {
Expand Down
3 changes: 2 additions & 1 deletion js/Draw/MLP/Playable.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ class Playable extends Draggable {
this.pause();
this.updateStatus(
+(
this.getInput() instanceof InputLayer &&
(this.getInput() instanceof InputLayer ||
this.getInput() instanceof DigitComponent) &&
(isEval || this.getOutput() instanceof OutputLayer)
),
);
Expand Down
78 changes: 78 additions & 0 deletions js/HandWritten/DigitComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
class DigitComponent extends Component {
constructor(x, y) {
super(x, y, 550);
this.shrank = true;
this.neuronAlignment = "right";
this.shape = [1, 784];
this.grid = new DigitInputGrid(0, 0);
this.clearButton = new TextButton("Clear shortcut: R", () => {
this.grid.clear();
}).setDimensions(this.grid.w, 25);
this.initialize();
}

getData() {
return [this.grid.values.flat()];
}

fetchNext() {}

initialize() {
this.inputDot.destroy();
this.inputDot = null;
this.outputDot.setColor("cyan");
this.adjustNeurons();
this.postUpdateCoordinates();
}

postUpdateCoordinates() {
this.grid.setCoordinates(this.x + 25, this.y + 30);
this.clearButton.setCoordinates(this.x + 25, this.y + this.h - 30);
super.postUpdateCoordinates();
}

adjustNeurons() {
const gridSize = this.grid.gridSize;
const neuronNum = gridSize * gridSize;
this.adjustNeuronNum(neuronNum);
this.setShownNeuronsNum(neuronNum > 5 ? 5 : neuronNum);
}

setCoordinates(x, y) {
super.setCoordinates(x, y);
this.postUpdateCoordinates();
}

getPressables() {
return [this.removeButton, this.clearButton, , this.outputDot, this.grid];
}

doubleClicked() {}

handleKeyPressed(k) {
iManager.isHovered(this) && k == "r" && this.grid.clear();
}

show() {
const middleX = this.x + this.w / 2;
const commands = [
{ func: "rect", args: [this.x, this.y, this.w, this.h, 10] },
{ func: "textAlign", args: [CENTER, CENTER] },
{
func: "text",
args: ["Grid Input", middleX, this.y - 10],
},
];

executeDrawingCommands(commands);
}

draw() {
super.draw();
this.show();
this.isShrank() && this.showInfoBox();
this.neurons.forEach((neuron) => neuron.draw());
this.grid.draw();
this.clearButton.draw();
}
}
197 changes: 139 additions & 58 deletions js/HandWritten/DigitInputGrid.js
Original file line number Diff line number Diff line change
@@ -1,89 +1,170 @@
class DigitInputGrid extends Component {
class DigitInputGrid extends Draggable {
constructor(x, y) {
super(x, y, 400);
this.shrank = true;
this.neuronAlignment = "right";
super(x, y);
this.gridSize = 28;
this.grid = Array.from({ length: this.gridSize }, () =>
Array(this.gridSize).fill(0),
this.cellSize = 10;
this.setDimensions(
this.gridSize * this.cellSize,
this.gridSize * this.cellSize,
);
this.initialize();
this.clear();
this.drawings = [];
}

initialize() {
this.inputDot.destroy();
this.inputDot = null;
this.outputDot.setColor("cyan");
this.adjustNeurons();
this.postUpdateCoordinates();
clear() {
this.drawings = [];
this.values = this.createEmptyGrid();
}

adjustNeurons() {
const neuronNum = this.gridSize * this.gridSize;
this.adjustNeuronNum(neuronNum);
this.setShownNeuronsNum(neuronNum > 5 ? 5 : neuronNum);
createEmptyGrid() {
return Array.from({ length: this.gridSize }, () =>
Array(this.gridSize).fill(0),
);
}

setCoordinates(x, y) {
super.setCoordinates(x, y);
this.postUpdateCoordinates();
this.x = x;
this.y = y;
}

getPressables() {
return [this.removeButton];
handlePressed() {
iManager.checkRollout(this);
}

doubleClicked() {}
handleDrag(_x, _y) {
const { mouseX, mouseY, pmouseX, pmouseY } = getCurrentMouseCoordinates();
const { x, y } = iManager.getAbsoluteCoordinates(mouseX, mouseY);
const { x: px, y: py } = iManager.getAbsoluteCoordinates(pmouseX, pmouseY);

this.drawings.push(this.getClampedCoordinates(x, y, px, py));
}

getClampedCoordinates(x, y, px, py) {
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
return {
x1: clamp(x - this.x, 0, this.w),
y1: clamp(y - this.y, 0, this.h),
x2: clamp(px - this.x, 0, this.w),
y2: clamp(py - this.y, 0, this.h),
};
}

showGrid() {
const commands = [{ func: "stroke", args: [0, 150] }];
const cellSize = 10;
const commands = [{ func: "stroke", args: [0, 50] }];
const offset = this.gridSize * this.cellSize;

for (let i = 0; i <= this.gridSize; i++) {
const offSet1 = i * cellSize;
const offset2 = this.gridSize * cellSize;
const x = this.x + 25;
const y = this.y + 30;
commands.push({
func: "line",
args: [x + offSet1, y, x + offSet1, y + offset2],
});
commands.push({
func: "line",
args: [x, y + offSet1, x + offset2, y + offSet1],
});
const pos = i * this.cellSize;
commands.push(
{
func: "line",
args: [this.x + pos, this.y, this.x + pos, this.y + offset],
},
{
func: "line",
args: [this.x, this.y + pos, this.x + offset, this.y + pos],
},
);
}

executeDrawingCommands(commands);
}

show() {
const middleX = this.x + this.w / 2;
showDrawings() {
const commands = [
{ func: "rect", args: [this.x, this.y, this.w, this.h, 10] },
{ func: "textAlign", args: [CENTER, CENTER] },
{
func: "text",
args: ["Grid Input", middleX, this.y - 10],
},
{ func: "stroke", args: [0] },
{ func: "strokeWeight", args: [4] },
];

for (const { x1, y1, x2, y2 } of this.drawings) {
commands.push({
func: "line",
args: [this.x + x1, this.y + y1, this.x + x2, this.y + y2],
});
}

executeDrawingCommands(commands);
this.showGrid();
}

draw() {
super.draw();
this.show();
this.isShrank() && this.showInfoBox();

this.neurons.forEach((neuron) => neuron.draw());
LoadingIndiactor.drawText(
this.x,
this.y,
this.w,
this.h,
"Work In Progress",
35,
);
this.showGrid();
this.showDrawings();
this.showValues();
}

convertDrawingsToValues() {
this.values = this.createEmptyGrid();

for (const { x1, y1, x2, y2 } of this.drawings) {
this.drawLineOnValues(
Math.min(Math.floor(x1 / this.cellSize), 27),
Math.min(Math.floor(y1 / this.cellSize), 27),
Math.min(Math.floor(x2 / this.cellSize), 27),
Math.min(Math.floor(y2 / this.cellSize), 27),
);
}

this.normalizeValues();
}

normalizeValues() {
const maxValue = Math.max(...this.values.flat());
if (maxValue === 0) return;

for (let i = 0; i < this.gridSize; i++) {
for (let j = 0; j < this.gridSize; j++) {
this.values[i][j] = Math.floor((this.values[i][j] / maxValue) * 255);
}
}
}

// Bresenham's Algorithm
drawLineOnValues(x1, y1, x2, y2) {
const dx = Math.abs(x2 - x1);
const dy = Math.abs(y2 - y1);
const sx = x1 < x2 ? 1 : -1;
const sy = y1 < y2 ? 1 : -1;
let err = dx - dy;

while (true) {
this.values[y1][x1] = Math.min(this.values[y1][x1] + 30, 255);
if (x1 === x2 && y1 === y2) break;

const e2 = err * 2;
if (e2 > -dy) {
err -= dy;
x1 += sx;
}
if (e2 < dx) {
err += dx;
y1 += sy;
}
}
}

showValues() {
this.convertDrawingsToValues();
const commands = [];
const cellSize = this.cellSize / 2;

for (let i = 0; i < this.gridSize; i++) {
for (let j = 0; j < this.gridSize; j++) {
const colorValue = this.values[i][j];
commands.push(
{ func: "fill", args: [colorValue] },
{
func: "rect",
args: [
this.x + this.w + 25 + j * cellSize,
this.y + (this.h - cellSize * this.gridSize) / 2 + i * cellSize,
cellSize,
cellSize,
],
},
);
}
}

executeDrawingCommands(commands);
}
}
Loading

0 comments on commit 21346b0

Please sign in to comment.