Behind the Screens: Visuall esthetic of Revit Reports

Niko G.
10 min readMay 23, 2023

--

Have you ever wondered why reports from programs arrive so unreadable? I’m not saying they’re illogical, quite the contrary. But to immediately grasp what’s happening can be difficult, and to do it quickly is often simply impossible. For example, instantly understanding something like “How many similar errors do you have” can be a real challenge. Today, I’m going to share with you how I tackled this problem in 20 minutes. Let’s just say, I didn’t solve it, but merely set a course towards the right solution.

The Heart of the Matter

For one of the projects, a large number of warnings were discovered. I have a lot of files there, so it was important to at least visually understand which errors repeat most frequently. I didn’t need some heavy-duty tools, like PowerBI or even Excel. I had no issue reviewing the reports, I just wanted a bit more convenience. For those who don’t remember, let me remind you what a typical Revit report looks like.

In my opinion, this is unreadable stuff. However, again, it’s well-structured, which is exactly what we need. You may ask me, “But what about the standard error viewer?” To which I’d respond, “You can’t even increase the viewing screen size there, let alone count the types of errors.”

Alright, I confess, I just wanted to revisit my HTML skills. I hope that takes the edge off the criticism (though I can’t be certain). BTW if you want to learn HTML and CSS I think you need this website.

In summary, I want the report to look good with minimal effort. Remember that? Let’s continue.

Tools

The report itself is just a regular HTML file with no styles configured!

All we have in our styles is the text layout — and that too, on every line! What a mess. Where is .css!! Alright, I’m exaggerating, I understand why it was done this way, I just wanted to see a bit of beauty. So I’ve touched on CSS, which is an important point. For those of you who don’t know, CSS is, in layman’s terms, the style of your HTML. Below I’ll include a picture for clarity. I think it effectively illustrates my point.

So, as you can see, HTML is the skeleton of our project. Indeed, it’s where all the markup and information are contained. Now, our job is to refine it, and make it easily digestible using CSS — in other words, to create a facade. There’s an important rule here: we mustn’t change the HTML itself, otherwise, we’ll have to manually edit each report. As you may recall, my aim is to make everything fast, yet aesthetically pleasing. So, let’s use a free online service, Codepen.

This resource will help us to make visible and quick changes. Alright, as you can see, I’ve decided to dive into the code. Not the most optimal choice, but why not? After all, I’m not writing a lesson, but sharing my day-to-day work with you. Maybe someone will find it interesting to see the kind of “nonsense” BIM specialists can deal with. Well, that’s a bit of poetry, I got sidetracked. Let’s continue.

Coding

For those of you who’ve never written in HTML, I highly recommend learning at least the basics. Then, it won’t be as daunting to look at all those “tags” in the file you’ll see later on. And as you may have noticed, almost all reports are generated in HTML. Remember those reports from Navisworks? Spoiler: I’m going to tackle that too. Firstly, we need to take all the markup from our HTML file. This can be done either by “right-clicking” on the page and copying the code or simply opening your file in an IDE, any of your preference. Below is an example of the code we see on the “backside” of our report. This is exactly what we need.


<html><p><center><h1> 225_01_Arch_SP_PD_R21_detached Error Report (22.05.2023 14:18:44) </h1></center></p>
<p><table border=on> <th style="width:'50%'; vertical-align:top;"> <center> Error message </center> </th>
<th style="width:'50%'; vertical-align:top;"><center> Elements </center> </th>
<tr> <td style="vertical-align:top;"> Room Tag is outside of its Room. Enable Leader or move Room Tag within its Room. </td>
<td> Вид "План этажа: *Зуй План 1 этажа" : Room Tags : АР-Марка-Помещения-Основная : Имя : id 9837190 </td> </tr>
<tr> <td style="vertical-align:top;"> Room Tag is outside of its Room. Enable Leader or move Room Tag within its Room. </td>
<td> Вид "План этажа: *Пров План 1 эт Sобщая" : Room Tags : АР-Марка-Помещения-Основная : Имя, Площадь : id 13360901 </td> </tr>
<tr> <td style="vertical-align:top;"> Room Tag is outside of its Room. Enable Leader or move Room Tag within its Room. </td>
<td> Вид "План этажа: *Л План П1 эт" : Room Tags : АР-Марка-Помещения-Основная : Имя : id 14628284 </td> </tr>
<tr> <td style="vertical-align:top;"> Room Tag is outside of its Room. Enable Leader or move Room Tag within its Room. </td>
<td> Вид "План этажа: *Л План 6 эт" : Room Tags : АР-Марка-Помещения-Основная : Имя : id 14638443 </td> </tr>
<tr> <td style="vertical-align:top;"> Room Tag is outside of its Room. Enable Leader or move Room Tag within its Room. </td>
<td> Вид "План этажа: *ЗЗ План 3 этажа" : Room Tags : АР-Марка-Помещения-Основная : Имя, Площадь, Номер : id 15899908 </td> </tr>
<tr> <td style="vertical-align:top;"> Room Tag is outside of its Room. Enable Leader or move Room Tag within its Room. </td>

Let’s open CodePen and paste our HTML into the pen with the same name. And what do we see below? Aha, our report is still there. Now we are going to get creative and make some changes to it.

Firstly, let’s copy the template and see what it looks like. Well, as I said, it looks the same as if we just open our file in the browser.

As you can see, in this editor, you can immediately add styles in CSS and even JS. I’ll start with something small, specifically CSS. I won’t bore you with every line. I’ll add a description to the CSS code and briefly go over what it generally does.


body {
font-family: Arial, sans-serif; // Sets the default font for the body element to Arial, if Arial is not available, a sans-serif font is used.
padding: 20px; // Creates a 20px space (padding) around the contents of the body element.
text-align: center; // Aligns the text within the body to the center of its container.
}

h1 {
font-size: 20px; // Sets the font size of all h1 elements to 20px.
color: #333; // Sets the text color of all h1 elements to a dark gray (#333).
}

table {
width: 50%; // Sets the width of the table to be 50% of its container's width.
border-collapse: collapse; // Removes the space between table borders, making them into a single border.
margin: 0 auto; // Centers the table horizontally within its container, as the left and right margins are automatically equal.
}

th, td {
padding: 15px; // Adds 15px of space (padding) around the contents of table header (th) and table data (td) cells.
text-align: left; // Aligns the text within the th and td cells to the left of their containers.
border-bottom: 1px solid #ddd; // Adds a 1px solid light gray (#ddd) bottom border to each th and td cell.
}

tr:hover {
background-color: #f5f5f5; // Changes the background color of a table row (tr) to light gray (#f5f5f5) when the user hovers over it.
}

.highlight-red {
background-color: #FF0000; // Sets the background color of elements with the class "highlight-red" to red (#FF0000).
}

.highlight-green {
background-color: #98FB98; // Sets the background color of elements with the class "highlight-green" to pale green (#98FB98).
}

In short: This CSS code provides style and layout instructions for a webpage. It sets the body’s text alignment and padding and declares the font style. For the ‘h1’ headings, it sets the font size and color. It also configures the table’s appearance, such as its width, border style, and center alignment. Moreover, it applies styling rules for table cells (both headers ‘th’ and data cells ‘td’), including padding, text alignment, and bottom border.

Now let’s see what we’ve got. Let’s apply the styles and take a look at the result.

The image at the top is unstyled, the one below is styled. It turned out quite nicely. The columns became restricted, the font was changed, and the table itself changed its format.

Now let’s move on to the interactivity. We have many repeating cells in the Error message. What if we “collapse” them, meaning, give them the ability to expand? We have an idea, so let’s proceed with the implementation.

This time, we’ll need some JS code. As before, I’ll provide comments on it, saving time by not going into a detailed explanation.

// First, we find all the rows in the table
var rows = document.querySelectorAll("table tr");

// We use a Map to store references to cells we want to merge
var cellsToMerge = new Map();

// We also create a Map to store a list of "Elements" cells for each error type
var associatedCells = new Map();

// We loop over each row
for (let row of rows) {
// We find the first cell in the row (the error message cell)
let cell = row.cells[0];
let associatedCell = row.cells[1]; // The "Elements" cell

// If we've already seen this error, we add the cell to the list of cells to merge
// and add the corresponding "Elements" cell to the list of associated cells
if (cellsToMerge.has(cell.textContent)) {
cellsToMerge.get(cell.textContent).push(cell);
associatedCells.get(cell.textContent).push(associatedCell);
}
// Otherwise, we create a new list for this error and a new list of associated cells
else {
cellsToMerge.set(cell.textContent, [cell]);
associatedCells.set(cell.textContent, [associatedCell]);
}
}

// Now we go over each list of cells and merge them
for (let [key, cells] of cellsToMerge) {
if (cells.length > 1) {
// We set the rowspan attribute on the first cell
cells[0].setAttribute("rowspan", cells.length);

// We remove all the other cells
for (let i = 1; i < cells.length; i++) {
cells[i].remove();
}
}

// We add an event handler to the first cell (the error message cell)
cells[0].addEventListener('click', function() {
// We toggle visibility of all associated "Elements" cells
for (let cell of associatedCells.get(key)) {
if (cell.style.display === 'none') {
cell.style.display = '';
} else {
cell.style.display = 'none';
}
}
});

// We set the visibility of all associated "Elements" cells to 'none' by default
for (let cell of associatedCells.get(key)) {
cell.style.display = 'none';
}

// We create and add a new cell with the number of errors in this error message
var newCell = document.createElement("td");
newCell.textContent = associatedCells.get(key).length;
cells[0].parentNode.appendChild(newCell);
}

// We create a button to hide all elements
var collapseButton = document.createElement("button");
collapseButton.textContent = "Hide all";
collapseButton.addEventListener('click', function() {
for (let cell of associatedCells.values()) {
for (let c of cell) {
c.style.display = 'none';
}
}
});

For those too lazy to “read” the code, I’ve briefly described what it does below:

  1. It fetches all the rows in the HTML table.
  2. It creates two Maps, one for storing references to cells that will be merged, and another for storing a list of “Elements” cells for each unique error message.
  3. It loops over each row in the table, checking if the error message has been seen before. If it has, it adds the error message cell and the corresponding “Elements” cell to their respective lists in the Maps. If it hasn’t, it creates new lists for the error and the associated cells.
  4. It then loops over each list of cells to be merged. If there is more than one cell in a list, it sets the row span attribute of the first cell to the number of cells in the list and removes all other cells in the list. It also sets an event listener on the first cell to toggle the visibility of the associated “Elements” cells when the cell is clicked.
  5. It creates and adds a new cell to the row of the first cell, which shows the number of times the error message appears in the table.
  6. It creates a button that, when clicked, hides all “Elements” cells.
  7. Finally, it adds this button to a container in the document.

And now, it’s time to apply it:

Now that’s more like it! Our table is now not only readable but also interactive. We can easily see both the number of identical errors and the length has been reduced. With quite simple solutions, we have transformed our HTML.

What’s next?

Now, let’s save the result. Thankfully, CodePen allows us to download our work as an archive. All you’ll have to do is unzip the result, and you’ll be able to see everything locally. For me, the online version is enough. I just take another HTML report, copy it, and get the same result.

And here comes your question. “Why?”, to be honest, I answered this before, I just did it for aesthetics, nothing more. I just wanted to make working with reports more convenient. To be curious means to learn constantly. That’s what I try to do every day.

If you found this intriguing, don’t forget to share the content, and I’ll keep delighting you with more insights from the life of a BIM manager.

--

--