aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/app
diff options
context:
space:
mode:
authorDanijel Andjelkovic <adanijel99@gmail.com>2022-04-07 15:14:20 +0200
committerDanijel Andjelkovic <adanijel99@gmail.com>2022-04-07 15:14:20 +0200
commit9174136e033421beec30eb3cc574d6e37d090857 (patch)
tree0b94e68d095cdf36821237910ed83c2fd4f13b2e /frontend/src/app
parent724000d1dc30f456d77d39a233a309bb9e36f5a9 (diff)
Dodao graph komponentu za brzo iscrtavanje grafa neuronske mreze.
Diffstat (limited to 'frontend/src/app')
-rw-r--r--frontend/src/app/_elements/graph/graph.component.css0
-rw-r--r--frontend/src/app/_elements/graph/graph.component.html3
-rw-r--r--frontend/src/app/_elements/graph/graph.component.spec.ts25
-rw-r--r--frontend/src/app/_elements/graph/graph.component.ts145
-rw-r--r--frontend/src/app/_elements/item-model/item-model.component.html3
-rw-r--r--frontend/src/app/_elements/model-load/model-load.component.html6
-rw-r--r--frontend/src/app/_elements/model-load/model-load.component.ts9
-rw-r--r--frontend/src/app/app.module.ts4
8 files changed, 189 insertions, 6 deletions
diff --git a/frontend/src/app/_elements/graph/graph.component.css b/frontend/src/app/_elements/graph/graph.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/frontend/src/app/_elements/graph/graph.component.css
diff --git a/frontend/src/app/_elements/graph/graph.component.html b/frontend/src/app/_elements/graph/graph.component.html
new file mode 100644
index 00000000..527d3f1a
--- /dev/null
+++ b/frontend/src/app/_elements/graph/graph.component.html
@@ -0,0 +1,3 @@
+<div id="graphWrapper" class="w-100" style="height: 16rem;">
+ <canvas id="graphCanvas" class="border"></canvas>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/graph/graph.component.spec.ts b/frontend/src/app/_elements/graph/graph.component.spec.ts
new file mode 100644
index 00000000..99783d42
--- /dev/null
+++ b/frontend/src/app/_elements/graph/graph.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { GraphComponent } from './graph.component';
+
+describe('GraphComponent', () => {
+ let component: GraphComponent;
+ let fixture: ComponentFixture<GraphComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ GraphComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(GraphComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_elements/graph/graph.component.ts b/frontend/src/app/_elements/graph/graph.component.ts
new file mode 100644
index 00000000..c17e8906
--- /dev/null
+++ b/frontend/src/app/_elements/graph/graph.component.ts
@@ -0,0 +1,145 @@
+import { Component, Input, OnInit } from '@angular/core';
+import Dataset from 'src/app/_data/Dataset';
+import Model from 'src/app/_data/Model';
+
+@Component({
+ selector: 'app-graph',
+ templateUrl: './graph.component.html',
+ styleUrls: ['./graph.component.css']
+})
+export class GraphComponent implements OnInit {
+
+ @Input() model?: Model;
+ @Input() inputCols: number = 1;
+
+ @Input() lineThickness: number = 5;
+ @Input() nodeRadius: number = 15;
+ @Input() lineColor: string = '#ff0000';
+ @Input() nodeColor: string = '#222277';
+ @Input() inputNodeColor: string = '#44ee22';
+ @Input() outputNodeColor: string = '#559977';
+
+ private wrapper?: HTMLDivElement;
+ private canvas?: HTMLCanvasElement;
+ private ctx?: CanvasRenderingContext2D;
+
+ constructor() { }
+
+ ngOnInit(): void {
+ this.wrapper = (<HTMLDivElement>document.getElementById('graphWrapper'));
+ this.canvas = (<HTMLCanvasElement>document.getElementById('graphCanvas'));
+ const ctx = this.canvas.getContext('2d');
+ if (ctx) {
+ this.ctx = ctx;
+ } else {
+ console.warn('Could not get canvas context!');
+ }
+
+ window.addEventListener('resize', () => { this.resize() });
+ this.update();
+ this.resize();
+
+ /*setInterval(() => {
+ this.update();
+ }, 5000);*/
+ }
+
+ layers?: Node[][];
+
+ update() {
+ this.layers = [];
+
+ let inputNodeIndex = 0;
+ const inputLayer: Node[] = [];
+ while (inputNodeIndex < this.inputCols) {
+ const x = 0.5 / (this.model!.hiddenLayers + 2);
+ const y = (inputNodeIndex + 0.5) / this.inputCols;
+ const node = new Node(x, y, this.inputNodeColor);
+ inputLayer.push(node);
+ inputNodeIndex += 1;
+ }
+ this.layers.push(inputLayer);
+
+ let layerIndex = 1;
+ while (layerIndex < this.model!.hiddenLayers + 1) {
+ const newLayer: Node[] = [];
+ let nodeIndex = 0;
+ while (nodeIndex < this.model!.hiddenLayerNeurons) {
+ const x = (layerIndex + 0.5) / (this.model!.hiddenLayers + 2);
+ const y = (nodeIndex + 0.5) / this.model!.hiddenLayerNeurons;
+ const node = new Node(x, y, this.nodeColor);
+ newLayer.push(node);
+ nodeIndex += 1;
+ }
+ this.layers.push(newLayer);
+ layerIndex += 1;
+ }
+
+ const outX = 1 - (0.5 / (this.model!.hiddenLayers + 2));
+ const outY = 0.5;
+ this.layers.push([new Node(outX, outY, this.outputNodeColor)])
+ this.draw();
+ }
+
+ draw() {
+ this.ctx!.clearRect(0, 0, this.canvas!.width, this.canvas!.height);
+
+ let index = 0;
+ while (index < this.layers!.length - 1) {
+ for (let node1 of this.layers![index]) {
+ for (let node2 of this.layers![index + 1]) {
+ this.drawLine(node1, node2);
+ }
+ }
+ index += 1;
+ }
+
+ for (let layer of this.layers!) {
+ for (let node of layer) {
+ this.drawNode(node);
+ }
+ }
+ }
+
+ drawLine(node1: Node, node2: Node) {
+ this.ctx!.strokeStyle = this.lineColor;
+ this.ctx!.beginPath();
+ this.ctx!.moveTo(node1.x * this.width, node1.y * this.height);
+ this.ctx!.lineTo(node2.x * this.width, node2.y * this.height);
+ this.ctx!.stroke();
+ }
+
+ drawNode(node: Node) {
+ this.ctx!.fillStyle = node.color;
+ this.ctx!.strokeStyle = '#000';
+ this.ctx!.beginPath();
+ this.ctx!.arc(node.x * this.width, node.y * this.height, this.nodeRadius, 0, 2 * Math.PI);
+ this.ctx!.fill();
+ this.ctx!.stroke();
+ }
+
+ width = 200;
+ height = 200;
+ ratio = 1;
+
+ resize() {
+ this.width = this.wrapper!.offsetWidth;
+ this.height = this.wrapper!.offsetHeight;
+ this.ratio = this.width / this.height;
+
+ if (this.canvas) {
+ this.canvas.width = this.width;
+ this.canvas.height = this.height;
+ }
+
+ this.draw();
+ }
+}
+
+class Node {
+ constructor(
+ public x: number,
+ public y: number,
+ public color: string
+ ) { }
+}
diff --git a/frontend/src/app/_elements/item-model/item-model.component.html b/frontend/src/app/_elements/item-model/item-model.component.html
index c8c1a36d..695c580e 100644
--- a/frontend/src/app/_elements/item-model/item-model.component.html
+++ b/frontend/src/app/_elements/item-model/item-model.component.html
@@ -1,4 +1,3 @@
-
<div class="card" style="min-width: 12rem;">
<div class="card-header">
{{model.name}}
@@ -9,6 +8,6 @@
{{"Datum kreiranja: " + model.dateCreated}}<br>
{{"Poslednje ažuriranje: " + model.lastUpdated}}<br>
</p>
- <app-annvisual class="align-items-center" [model]="model" style="width: 12rem"></app-annvisual>
+ <app-graph [model]="model"></app-graph>
</div>
</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/model-load/model-load.component.html b/frontend/src/app/_elements/model-load/model-load.component.html
index 0c6735a9..f7d8a077 100644
--- a/frontend/src/app/_elements/model-load/model-load.component.html
+++ b/frontend/src/app/_elements/model-load/model-load.component.html
@@ -43,7 +43,8 @@
<div class="col-1">
<input type="number" min="1" class="form-control" name="hiddenLayers"
[(ngModel)]="newModel.hiddenLayers"
- (change)="newModel.hiddenLayerActivationFunctions = [].constructor(newModel.hiddenLayers).fill(newModel.hiddenLayerActivationFunctions[0])">
+ (change)="newModel.hiddenLayerActivationFunctions = [].constructor(newModel.hiddenLayers).fill(newModel.hiddenLayerActivationFunctions[0])"
+ (ngModelChange)="updateGraph()">
</div>
</div>
@@ -69,7 +70,7 @@
</div>
<div class="col-1">
<input type="number" min="1" class="form-control" name="hiddenLayerNeurons"
- [(ngModel)]="newModel.hiddenLayerNeurons">
+ [(ngModel)]="newModel.hiddenLayerNeurons" (ngModelChange)="updateGraph()">
</div>
</div>
@@ -212,6 +213,7 @@
</div>
</div>
</div>
+ <app-graph [model]="newModel" [inputCols]="1"></app-graph>
<div class="form-group row mt-5 mb-3">
<div class="col"></div>
<button class="btn btn-lg col-4" style="background-color:#003459; color:white;" (click)="addModel();">Sačuvaj
diff --git a/frontend/src/app/_elements/model-load/model-load.component.ts b/frontend/src/app/_elements/model-load/model-load.component.ts
index 1d38de68..663e414f 100644
--- a/frontend/src/app/_elements/model-load/model-load.component.ts
+++ b/frontend/src/app/_elements/model-load/model-load.component.ts
@@ -1,7 +1,8 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, OnInit, ViewChild } from '@angular/core';
import Shared from 'src/app/Shared';
import Model, { ActivationFunction, Encoding, LossFunction, LossFunctionBinaryClassification, LossFunctionMultiClassification, LossFunctionRegression, Metrics, MetricsBinaryClassification, MetricsMultiClassification, MetricsRegression, NullValueOptions, Optimizer, ProblemType } from 'src/app/_data/Model';
import { ModelsService } from 'src/app/_services/models.service';
+import { GraphComponent } from '../graph/graph.component';
@Component({
selector: 'app-model-load',
@@ -10,6 +11,8 @@ import { ModelsService } from 'src/app/_services/models.service';
})
export class ModelLoadComponent implements OnInit {
+ @ViewChild(GraphComponent) graph!: GraphComponent;
+
newModel: Model = new Model();
ProblemType = ProblemType;
@@ -33,6 +36,10 @@ export class ModelLoadComponent implements OnInit {
ngOnInit(): void {
}
+ updateGraph() {
+ this.graph.update();
+ }
+
getMetrics() {
this.newModel.metrics = [];
let cb = document.getElementsByName("cbmetrics");
diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts
index c3a2ce7a..0c1a4162 100644
--- a/frontend/src/app/app.module.ts
+++ b/frontend/src/app/app.module.ts
@@ -43,6 +43,7 @@ import { LoadingComponent } from './_elements/loading/loading.component';
import { ModelLoadComponent } from './_elements/model-load/model-load.component';
import { AlertDialogComponent } from './_modals/alert-dialog/alert-dialog.component';
import { AddNewDatasetComponent } from './_elements/add-new-dataset/add-new-dataset.component';
+import { GraphComponent } from './_elements/graph/graph.component';
@NgModule({
declarations: [
@@ -75,7 +76,8 @@ import { AddNewDatasetComponent } from './_elements/add-new-dataset/add-new-data
LoadingComponent,
ModelLoadComponent,
AlertDialogComponent,
- AddNewDatasetComponent
+ AddNewDatasetComponent,
+ GraphComponent
],
imports: [
BrowserModule,