Lesson 5 - Construct Model

In the previous section, we created a nice UI and connected some buttons to JavaScript functions. Let's add some proper functionality to the buttons now.

Construction Sequence#

This one is going to be fun. First, we will make a copy of the members object, then remove all members from the model. Then we will cycle all of the members and add a timeout function for each. When the timeout function executes, it will add the member to the model.

Here is the code!

app.constructModel = function () {
// Get the current model
const model = S3D.structure.get({ api_format: true });
// Create a function to clone (break reference) the members object
const clone = (value) => JSON.parse(JSON.stringify(value));
// Get a copy of the members object
const members = clone(model.members);
// Remove the members from the original model
// Notice the use of "of" here "of" will get
// the value of an item at index X in an array
// "in" will get the index of the item
for (let member_id of Object.keys(members)) {
S3D.structure.members.remove(member_id);
}
// Update the view
S3D.UI.update({ redraw: true });
// 1 second for the first member
let wait_time = 1000;
// Make the construction always take about 10 seconds
let wait_increment = 20000 / Object.keys(members).length;
// Loop each of the members and place them back in every X seconds
for (let member_id of Object.keys(members)) {
// Trigger the inner function after wait_time
setTimeout(function () {
// Get the next member
const member = members[member_id];
// Explicitly set the ID for this member.
member.ID = member_id;
// Add the member to the model
S3D.structure.members.add(member);
// Update the view
S3D.UI.update({ redraw: true });
}, wait_time);
// Increase the wait time for the next member
wait_time += wait_increment;
}
};

Let's discuss a few things going on here.

Clone#

Firstly, that clone thing. JavaScript will pass objects by reference. This means that if we simply said const members = model.members, then members would just be a reference to the original model.members. Therefore, when we remove all of the members from the model in the following for loop, members would be pointing to items that no longer exist.

A quick trick to make a copy of an object is to stringify it into JSON. This works because primitive values such as string, number and some others, don't pass by reference in JavaScript. Now we parse that string back to an object and voilà, our object now lives in a new piece of memory.

We can easily compact that function into a one-liner using an arrow function.

const clone = (value) => JSON.parse(JSON.stringify(value));

Set Timeout#

There is more than one way to achieve the visual effect of adding the members one-by-one. We might use the built in function setInterval instead, which will fire a function every x seconds until it is manually stopped.

In the above code we used it's sibiling setTimeout. This fires once at the end of the time given to it (in milliseconds). The idea is that we quickly loop every member, and create an instance of setTimeout. By the time the loop finishes, there will be as many instances of setTimeout as there is members in the model.

For each of these instances, we provide a "callback" function to execute when the timeout finishes. In the callback function, we get the next member to add, explicitly choose the ID of the member, add it back in, and re-render the view.

Before continuing to the next iteration to add the next timeout, we increment the wait_time for the next member. Therefore by the time the loop finishes, member 1 will have a timeout of 1s, the next member slightly more and so on. There would be drift from the time it takes for the loop to execute however, this is obviously not an issue for us here.

important

If the App appears to lag severly, try closing the developer tools. This is a common issue with Google Chrome.

Next Section#

Alright, try it out and let's move on! Next up, locating the longest member.