Skip to main content

Overview

The Data Visualization feature transforms IFC building data into interactive charts, providing instant insights into your project’s composition. Built with Chart.js, the system automatically analyzes element types, building storeys, and material distributions.
Charts are interactive - click on any bar or segment to isolate those elements in the 3D viewer!

Chart Types

The application supports two primary chart types for different analytical perspectives:

Bar Chart

Elements By TypeDisplays count of structural elements (walls, slabs, beams) with color-coded bars for easy comparison.

Doughnut Chart

Elements By LevelShows distribution of elements across building storeys with proportional segments.

Core Technology

The visualization system is built on industry-standard charting technology:
import {
  Chart,
  BarController,
  BarElement,
  CategoryScale,
  LinearScale,
  Tooltip,
  DoughnutController,
  ArcElement
} from "chart.js";

Chart.register(BarController, BarElement, CategoryScale, LinearScale, Tooltip, DoughnutController, ArcElement);
  • Chart.js 4.4.8: Modern, flexible JavaScript charting library
  • Modular Architecture: Only necessary chart types are loaded for optimal performance
  • Interactive Tooltips: Hover over any element to see exact counts

ChartData Component

The custom ChartData component integrates with OpenBIM Components to extract and process IFC data:
export class ChartData extends OBC.Component {
  enabled: boolean = true;
  static uuid = OBC.UUID.create();
  fragmentGroup = this.components.get(OBC.FragmentsManager);

  constructor(components: OBC.Components){
    super(components);
    components.add(ChartData.uuid, this);
  }
}

Element Counting by Type

The system automatically counts three primary structural element types:

Data Collection

getAllEntitiesOfType = async ()=>{
  let data: ChartData[] = [];
  for(var [id,model] of this.fragmentGroup.groups){
    let walls = await this.getPropertiesOfSpecificType(WEBIFC.IFCWALL, "IfcWall","rgba(255, 0, 0, 0.5)");
    if(walls.expressIds.length ==0) 
      walls = await this.getPropertiesOfSpecificType(WEBIFC.IFCWALLSTANDARDCASE,"IfcWallStandardCase", "rgba(255, 0, 0, 0.5)");
    
    const slabs = await this.getPropertiesOfSpecificType(WEBIFC.IFCSLAB, "IfcSlab","rgba(0, 150, 255, 0.5)");
    const beams = await this.getPropertiesOfSpecificType(WEBIFC.IFCBEAM,"IfcBeam","rgba(0, 255, 0, 0.5)");
    data.push(walls);
    data.push(slabs);
    data.push(beams);
  }
  return data;
}

Element Type Colors

Red (rgba(255, 0, 0, 0.5))Includes both IFCWALL and IFCWALLSTANDARDCASE types with fallback support.

Building Storey Analysis

The doughnut chart provides spatial distribution analysis across building levels:
getPropertiesOfSpecificLevel = async ()=>{
  const indexer = this.components.get(OBC.IfcRelationsIndexer);
  const usedColors = new Set<string>();
  let levelsData: ChartData[] = [];
  
  for(const [_, model] of this.fragmentGroup.groups){
    const levelOfModel = await model.getAllPropertiesOfType(WEBIFC.IFCBUILDINGSTOREY);
    if(!levelOfModel) continue;
    
    for(const [expressId, properties] of Object.entries(levelOfModel)){
      let pieData : ChartData = {
        expressIds: [], 
        elementType: properties.Name.value, 
        color: this.generateUniqueRGB(usedColors)
      };
      
      const expressIdAsNUmber = parseInt(expressId) as number;
      const allElementInThisLevel = indexer.getEntitiesWithRelation(model,"ContainedInStructure",expressIdAsNUmber);
      allElementInThisLevel.forEach(item=>pieData.expressIds.push(item));
      levelsData.push(pieData);
    }
  }
  return levelsData;
}

Key Features

The system discovers all IFCBUILDINGSTOREY entities in the model and extracts their names and contained elements.
Each building storey receives a unique RGB color for clear visual distinction in the chart.
Uses the IfcRelationsIndexer to find all elements contained within each spatial structure.
Tracks Express IDs of all elements on each floor for precise counting and isolation.

Unique Color Generation

The system ensures each chart segment has a distinct color:
generateUniqueRGB=(usedColors: Set<string>)=> {
  let color;
  do {
    const r = Math.floor(Math.random() * 256);
    const g = Math.floor(Math.random() * 256);
    const b = Math.floor(Math.random() * 256);
    color = `rgb(${r}, ${g}, ${b})`;
  } while (usedColors.has(color));

  usedColors.add(color);
  return color;
}
The color generator uses a Set to track used colors, preventing duplicates and ensuring maximum visual clarity.

Chart Configuration

The chart data structure follows Chart.js standards with custom styling:
chartData = (data:ChartData[], chartType:string)=>{
  let singleDataset : BarDataset = {
    type:chartType as ChartType,
    data:{
      labels:data.map(item=>{return item.elementType}),
      datasets:[{
        label:"Quantity",
        data: data.map(item=>{return item.expressIds.length}),
        backgroundColor: data.map(item=>{return item.color}),
        borderWidth: [2,2,2],
        borderRadius: [8,8,8],
        borderColor: [ "darkred", "darkblue", "darkgreen"]
      }]
    }
  }
  return singleDataset;
}

Visual Styling

Border Width

2px borders for clear separation between elements

Border Radius

8px rounded corners for modern, polished appearance

Border Colors

Dark borders (darkred, darkblue, darkgreen) for enhanced contrast

Interactive Features

Chart Initialization

The bar chart initializes with element type data:
const initialize = ()=>{
  setTimeout(async ()=>{
    if(chart) chart.destroy();
    const canvas = document.getElementById("myChart") as HTMLCanvasElement;
    var data = await chartClass.getAllEntitiesOfType();
    const chartDataset = chartClass.chartData(data, 'bar');
    
    const fullChartData = {...chartDataset, ...OptionsData};

    if(!canvas) return;
    const ctx = canvas.getContext("2d");
    if(!ctx) return;
    
    chart = new Chart(ctx, fullChartData);
    hider.set(true);
  },0)
}
When a chart is initialized, all elements in the 3D viewer are hidden by default (hider.set(true)), preparing for interactive isolation.

Click Interaction - Bar Chart

Clicking a bar isolates those elements in the 3D viewer:
canvas.onclick = function(event){
  hider.set(true);
  let activePoints = chart?.getElementsAtEventForMode(event, "nearest", {intersect: true}, false);
  if(activePoints && activePoints.length>0){
    var index = activePoints[0].index;
    var label = chart?.data.labels[index];
    var value = chart?.data.datasets[0].data[index];

    var clickedBarData = data.filter(item=>item.elementType===label)[0];
    const models = fragmentManager.groups;
    for(const [id, model] of models){
      const fragmentMapOfBarIds = model.getFragmentMap(clickedBarData.expressIds);
      hider.isolate(fragmentMapOfBarIds);
    }

    const defaultColors = [
      "rgba(255, 0, 0, 0.7)",
      "rgba(0, 150, 255, 0.7)",
      "rgba(0, 255, 0, 0.7)",
    ];
    const clickedColor = "rgba(255, 255, 0, 0.7)";
    const currentColors = chart?.data.datasets[0].backgroundColor;

    for(let i =0; i<defaultColors.length; i++){
      currentColors[i] = defaultColors[i];
    }

    if(!currentColors) return;
    currentColors[index] = currentColors[index] === clickedColor ? defaultColors[index] : clickedColor;
    chart?.update();
  }
}

Click Behavior

1

Element Detection

Click event detects which bar was clicked using Chart.js “nearest” mode.
2

Data Retrieval

System retrieves all Express IDs associated with that element type.
3

3D Isolation

The Hider component isolates only those elements in the 3D viewer.
4

Visual Feedback

Clicked bar changes to yellow (rgba(255, 255, 0, 0.7)) to indicate active selection.

Click Interaction - Doughnut Chart

The doughnut chart provides similar isolation for building storeys:
canvas.onclick = function(event){
  hider.set(true);
  let activePoints = chart?.getElementsAtEventForMode(event, "nearest", {intersect: true}, false);
  if(activePoints && activePoints.length>0){
    var index = activePoints[0].index;
    var label = chart?.data.labels[index];
    var value = chart?.data.datasets[0].data[index];

    var clickedBarData = levelsData.filter(item=>item.elementType===label)[0];
    const models = fragmentManager.groups;
    for(const [modelId, model] of models){
      const fragmentIdMapFromSelectedChartELement = model.getFragmentMap(clickedBarData.expressIds);
      hider.isolate(fragmentIdMapFromSelectedChartELement);
    }
  }
}
Clicking a doughnut segment isolates all elements on that building storey, making it easy to focus on specific floors.

Chart Options and Styling

Bar Chart Configuration

const OptionsData = {
  options:{
    elements: {
      bar: {
        borderWidth: 5,
        borderRadius: 5
      }
    },
    plugins:{
      tooltip:{
        enabled: true,
        mode:"index",
        intersect:false,
      }
    },
  }
}

Doughnut Chart Configuration

The doughnut chart has specialized styling for compact display:
const canvas = document.getElementById("myChart") as HTMLCanvasElement;
canvas.style.maxWidth = "300px";
canvas.style.maxHeight = "300px";
canvas.style.display = "flex";
canvas.style.justifyContent = "center";
canvas.style.alignItems = "center";

const modifyOPtions = {
  ...OptionsData, 
  options:{
    ...OptionsData.options,
    layout:{
      padding:20,
    },
    scales:{
      x:{ display:false },
      y:{ display:false }
    },
    plugins:{
      ...OptionsData.options.plugins, 
      legend:{ display:false }
    }
  }
}
Max dimensions of 300x300px ensure compact, readable visualization.

User Interface

The chart panel provides intuitive controls:
return BUI.html`
  <bim-panel-section label="Charts" fixed style="display:flex; justify-content:center; align-items: center;">
    <bim-button @click=${initialize} label="RESTART CHART" icon="mi:add"></bim-button>
    <bim-dropdown name="type" @change=${dropDownOnClick}>
      <bim-option label="Elements By Type" value="bar"></bim-option>
      <bim-option label="Elements By Level" value ="doughnut"></bim-option>
    </bim-dropdown>
    <canvas id="myChart" width="300" height="200"></canvas>
  </bim-panel-section>
`

Control Elements

Restart Button

Regenerates the chart from current model data, useful after model changes

Chart Type Dropdown

Switch between Bar (element types) and Doughnut (building storeys) views

Canvas Element

300x200px canvas for rendering the interactive chart

Chart Switching Logic

const dropDownOnClick = async (e: Event)=>{
  const btn = e.target as BUI.Dropdown;
  const panelSection = btn.closest("bim-panel-section");
  const chartType= panelSection?.value.type[0];
  if(!chartType){
    alert("Select option from dropdown");
    return;
  }
  
  const levelsData = await chartClass.getPropertiesOfSpecificLevel();
  if(chartType==="bar"){
    initialize();
  }else if(chartType==="doughnut"){
    // Doughnut chart initialization
  }
}
Changing chart types destroys the previous chart instance to prevent memory leaks and ensure clean rendering.

Data Structure

The ChartData interface defines the structure for chart datasets:
export interface ChartData {
  expressIds: number[],
  elementType:string,
  color:string,
}

export interface BarDataset{
  type:string,
  data:{
    labels: string[],
    datasets:[{
      label:string,
      data: number[],
      backgroundColor: string[],
      borderWidth: number[],
      borderRadius: number[],
      borderColor: string[]
    }]
  }
}

ChartData Properties

Array of IFC Express IDs for all elements in this category, used for 3D isolation.
Human-readable label (e.g., “IfcWall”, “Level 1”) displayed on chart axes.
RGB/RGBA color string for visual representation in the chart.

Performance Considerations

Charts are generated asynchronously with a setTimeout wrapper to prevent UI blocking during data processing.
The system processes all loaded models (fragmentGroup.groups) to ensure multi-model projects are fully analyzed.

Best Practices

1

Load Model First

Ensure your IFC model is fully loaded before generating charts for accurate data.
2

Use Restart After Changes

Click “RESTART CHART” if you load additional models or modify the scene.
3

Click to Explore

Use chart interaction to isolate and inspect specific element types or building levels.
4

Switch Views

Toggle between bar and doughnut charts for different analytical perspectives.

Future Enhancements

Planned improvements to the visualization system:
  • Material distribution pie charts
  • Cost analysis visualization
  • Timeline/schedule Gantt charts
  • Custom filtering by property values
  • Export charts as images
  • Multi-model comparison charts

Build docs developers (and LLMs) love