iModel.js meets CSV (Part 1/3)

check out full sample | code diff

Roop Saini
iTwin.js
4 min readAug 29, 2019

--

Last week I got pulled into an email thread about reading data from a file and presenting it on an iModel.js viewport. It looked like a fun read until people started dropping @s on me. They wanted me to prepare a demo so we could share some code with a client.

Fine. Let’s do this.

What do we have here: An excel file that has a list of component ids and statuses.

I personally don’t like the idea of parsing an excel file. I would rather go with something simpler, like a CSV. Thank god for the export functionality in EXCEL.

Let’s get rid of the column names since they are not part of the data. Now we have a CSV file that looks like this:

Sweet. Next, we clone a blank copy of the Simple Viewer App (SVA) and configure it with the target iModel and project. Since it already has the viewport functionality, we can go ahead and extend it to fulfill the requirements of the demo. This is what our original model looks like:

I am sure you are wondering what those component IDs are for. That would be the gaskets; the gray spheres you see on the pipes. We need to highlight a select few that are listed in the file and display their status.

The first thing we need to figure out is how to read the CSV file into this app. It really depends on where the file is located. If it’s on the

  1. Frontend (client): create some sort of file upload feature.
  2. Backend (server): read the file and send it over to the frontend.

In this case, the file exists on the server. We will need to get the path of the file, read it and transfer that information on to the frontend. Now how exactly do we do that? Maybe there is a convenient iModel.js API that would call into the backend, open a file, read the data, parse it and return a nice array of information that we could then step through.

Yeah, that doesn’t exist.

But let’s see if we can make it happen.

iModel.js offers the ability to write your own custom RPC interface. This allows the frontend to directly call an asynchronous function which is forwarded onto the backend.

Let’s call ours FileReaderRpcInterface with a function fetchInfo. I copied some boilerplate from the documentation and ended up with the following interface definition:

We will call fetchInfo from the frontend to read the file data.

Now let’s create a corresponding backend implementation for this interface. Let’s see…what all do we need to do to get this data?

  1. Read the file — we can use fs for that.
  2. Parse the data — get an array of elements each with a component_id and status. I am sure we can find a package that can do that for us.

After a couple of dings on Google, I found csv-parse which will convert our CSV data into an array. Perfect.

Let’s get the boilerplate for our server-side RPC implementation, and write the fetchInfo function to accomplish the above tasks:

The last thing we need to do is register our RPC. We can do that on the backend by registering our RPC implementation class after the backend initializes. That would be after the iModelHost.startup() call:

On the frontend, we can do that by simply adding it to the list of supported RPCs under the rpcs.ts file.

And with that…we are ready to use our custom RPC!

Now, where in the frontend code should we read from the file?

A good place would be right after we open our iModel. At this point, we know we already have some data to work with. That would be under the _onIModelSelected function in App.tsx. Let’s add our interface call, build and run:

And there it is! The data from the CSV file…

…obtained using a convenient API that calls into the backend, opens a file, reads the data, parses it and returns a nice array of information that we can now step through.

And guess what? We just took the first step towards creating an immersive connection. I am going to go celebrate with some vending machine candy (click here to see what I got). In the next post: we will find the 3D coordinates of gaskets in this list.

-Roop, reporting live from the basement.

<- previous post | home | next post ->

--

--