How to simulate the neural network with JavaScript (attached source code)
Tags: webdev, javascript, programming, tutorial
Published: 2022-12-21 03:20:30


The target we will achieve:
[Neural network](https://youtu.be/hzqBsJzC75Y)

![Neural network](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mxtun0s6ew2u24l59eld.gif)

[[Click here to see more demonstrations including Digital Twins, GIS, VR, BIM, etc.]](https://www.hightopo.com/demos/en-index.html)

**Initialization**

The initialization work includes the preparation of colors, 3d scene, layout, 3d model, control pane, etc.

```
		var init = function() {
			// prepare 3d scene and datamodel
			var dm = new ht.DataModel(),
				g3d = window.g3d = new ht.graph3d.Graph3dView(dm);
			g3d.getBrightness = function() { return null; };
			g3d.isMovable = function(node) { return node.s('shape3d') !== 'custom'; };
			g3d.addToDOM();

			// create node and edges
			var edgeList = initDataModel(dm),

			// init the control pane and elastic layout
			forceLayout = new ht.layout.Force3dLayout(g3d);
                        // the core code
			forceLayout.onRelaxed = function() {
				edgeList.forEach(updatePipeline);
			};
			forceLayout.start();
			initFormPane(g3d);
		};
```


**Create Nodes and Edges**

After the environment is ready, let's create the nodes (balls) and edges. This step is quite simple, when nodes are created, we just need to put the source node and target node into their Edge.
There're two ways to set the source and target endpoint for one Edge:
1. Specify the source and target node when creating Edge, i.e. new ht.Edge(node1, node2);
2. Use edgeInstance.setSource() and edgeInstance.setTarget() after the Edge has been created

Meanwhile, we'll create one 3d pipeline to connect the source node and target node. Each pipeline will be saved in its corresponding edges.

```
		var createNode = function(dm) {
			var node = new ht.Node();
			node.s({
				'shape3d': 'sphere',
				'shape3d.color': randomColor()
			});
			node.s3(40, 40, 40);
			dm.add(node);
			return node;
		};

		var createEdge = function(dm, node1, node2) {
			// create one self-defined 3d pipeline
			// this pipeline will be used between source node and target node 
			var node = new ht.Node();
			node.s({
				'shape3d': 'custom', // self-defined 3d model
				'shape3d.color': '#ECE0D4',
				'layoutable': false
			});
			dm.add(node);

			// can specify the source node and target node when create the Edge.
			var edge = new ht.Edge(node1, node2);
			edge.a('pipeline', node); // use one attribute of edge to save the pipline
			edge.s('edge.color', 'rgba(0, 0, 0, 0)');
			dm.add(edge);

			return edge;
		};
```


**Update pipelines**

The core code of this project is to overload the "onRelaxed" function of ht.layout.Force3dLayout. 
The ht.layout.Force3dLayout class provides 3D force layouts, and constructors can input both DataModel and Graph3dView parameters. By default, only the unselected datas are laid out, and if the constructor parameter is Graph3dView, then the isMovable and isVisible functions of the view component will affect whether the data can be laid out, and the style layoutable attribute on the data can also be set to false to prevent datas from participating in the layout.
In this project, the updatePipeline function is created to update each pipeline: 
```
forceLayout.onRelaxed = function() {
				edgeList.forEach(updatePipeline);
			};
```

Now the main work is how to update the pipeline corresponding to their edges. Since we have saved the pipeline into each edge attribute, and the source and target node can be get from each edge by edge.getSourceAgent() and edge.getTargetAgent(), we can then use their position to recalculate the shape of the pipeline. 

```
		var updatePipeline = function(edge) {
			// get the pipeline from edge attribute
			var pipeline = edge.a('pipeline');
			pipeline.s3(1, 1, 1);
			pipeline.p3(0, 0, 0);

			// get the source node and target node
			var node1 = edge.getSourceAgent(),
				node2 = edge.getTargetAgent();
			// update the pipeline based on the position of source and target node
			pipeline.s('mat', createMatrix(node1.p3(), node2.p3(), 20));
		};

		var createMatrix = function(p1, p2, width) {
			var vec = [p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]],
				dist = ht.Default.getDistance(p1, p2);
			return ht.Default.createMatrix({
				s3: [width, dist, width], // size
				r3: [Math.PI/2 - Math.asin(vec[1]/dist), Math.atan2(vec[0], vec[2]), 0], // rotation
				rotationMode: 'xyz',
				t3: [(p1[0]+p2[0])/2, (p1[1]+p2[1])/2, (p1[2]+p2[2])/2]
			});
		};
```


At this time, the main work has been done. Let's take a look at the neural network:
[Neural network](https://www.hightopo.com/demo/pipeline/index.html)
To get the source code, just open the link and press F12.

[Find more cool demos here](https://hightopo.com/demos/en-index.html)