Skip to main content

Overview

The ChartData component extracts building element data from loaded IFC models and prepares it for visualization using Chart.js. It provides methods to analyze elements by type, by building level, and generate chart-ready datasets.

Class Definition

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);
  }
}
Location: src/bim-components/ChartData/index.ts:28

Properties

enabled
boolean
default:"true"
Flag indicating whether the component is active
uuid
string
required
Dynamically generated UUID identifier for the component instance
fragmentGroup
OBC.FragmentsManager
required
Reference to the FragmentsManager containing all loaded building models

Interfaces

ChartData Interface

Represents a collection of building elements of a specific type.
export interface ChartData {
  expressIds: number[],
  elementType: string,
  color: string,
}
Location: src/bim-components/ChartData/index.ts:7
expressIds
number[]
Array of IFC Express IDs identifying specific building elements
elementType
string
Human-readable element type name (e.g., “IfcWall”, “Ground Floor”, “IfcSlab”)
color
string
RGB color string for chart visualization (e.g., “rgba(255, 0, 0, 0.5)“)

BarDataset Interface

Chart.js compatible dataset structure for bar and pie charts.
export interface BarDataset {
  type: string,
  data: {
    labels: string[],
    datasets: [{
      label: string,
      data: number[],
      backgroundColor: string[],
      borderWidth: number[],
      borderRadius: number[],
      borderColor: string[]
    }]
  }
}
Location: src/bim-components/ChartData/index.ts:13
type
string
Chart type (e.g., “bar”, “pie”, “doughnut”)
data.labels
string[]
Array of label strings for each data point
data.datasets[0].label
string
Dataset label (e.g., “Quantity”)
data.datasets[0].data
number[]
Numeric values for each data point
data.datasets[0].backgroundColor
string[]
Background color for each bar/segment
data.datasets[0].borderWidth
number[]
Border width for each element
data.datasets[0].borderRadius
number[]
Border radius for rounded corners
data.datasets[0].borderColor
string[]
Border color for each element

Methods

getPropertiesOfSpecificLevel

Analyzes all building storeys (levels/floors) in loaded models and returns element counts per level.
getPropertiesOfSpecificLevel = async (): Promise<ChartData[]>
Location: src/bim-components/ChartData/index.ts:51
return
Promise<ChartData[]>
Array of ChartData objects, one per building level, containing all elements in that level
Process Flow:
  1. Iterates through all loaded models in FragmentsManager
  2. Extracts all IFCBUILDINGSTOREY entities
  3. For each level, finds all contained elements using spatial relationships
  4. Generates unique colors for each level
  5. Returns array with expressIds, level name, and color
Example:
const chartData = components.get(ChartData);
const levelData = await chartData.getPropertiesOfSpecificLevel();

// Result:
// [
//   {
//     expressIds: [1234, 1235, 1236, ...],
//     elementType: "Ground Floor",
//     color: "rgb(142, 68, 173)"
//   },
//   {
//     expressIds: [2234, 2235, 2236, ...],
//     elementType: "First Floor",
//     color: "rgb(52, 152, 219)"
//   }
// ]

console.log(`${levelData[0].elementType} has ${levelData[0].expressIds.length} elements`);
// Output: "Ground Floor has 245 elements"
Implementation:
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;
Source: src/bim-components/ChartData/index.ts:51-74

getPropertiesOfSpecificType

Extracts all elements of a specific IFC type from all loaded models.
getPropertiesOfSpecificType = async (
  typeNumber: number,
  elementTypeName: string,
  color: string
): Promise<ChartData>
Location: src/bim-components/ChartData/index.ts:76
typeNumber
number
required
IFC entity type number (e.g., WEBIFC.IFCWALL, WEBIFC.IFCSLAB)
elementTypeName
string
required
Human-readable name for the element type (e.g., “IfcWall”, “IfcSlab”)
color
string
required
RGBA color string for visualization (e.g., “rgba(255, 0, 0, 0.5)”)
return
Promise<ChartData>
ChartData object containing all expressIds of the specified type across all models
Example:
import * as WEBIFC from "web-ifc";

const chartData = components.get(ChartData);

// Get all walls
const walls = await chartData.getPropertiesOfSpecificType(
  WEBIFC.IFCWALL,
  "IfcWall",
  "rgba(255, 0, 0, 0.5)"
);

// Get all slabs
const slabs = await chartData.getPropertiesOfSpecificType(
  WEBIFC.IFCSLAB,
  "IfcSlab",
  "rgba(0, 150, 255, 0.5)"
);

console.log(`Found ${walls.expressIds.length} walls and ${slabs.expressIds.length} slabs`);
Implementation:
let bar: ChartData = {
  expressIds: [],
  elementType: elementTypeName,
  color
};

for (var [id, model] of this.fragmentGroup.groups) {
  const searchType = await model.getAllPropertiesOfType(typeNumber);
  if (!searchType) continue;
  
  for (var [expressId, properties] of Object.entries(searchType)) {
    bar.expressIds.push(parseInt(expressId, 10));
  }
}

return bar;
Source: src/bim-components/ChartData/index.ts:76-91

getAllEntitiesOfType

Convenience method that retrieves walls, slabs, and beams from all models.
getAllEntitiesOfType = async (): Promise<ChartData[]>
Location: src/bim-components/ChartData/index.ts:97
return
Promise<ChartData[]>
Array containing three ChartData objects: walls, slabs, and beams
Example:
const chartData = components.get(ChartData);
const entities = await chartData.getAllEntitiesOfType();

// Result:
// [
//   { expressIds: [...], elementType: "IfcWall", color: "rgba(255, 0, 0, 0.5)" },
//   { expressIds: [...], elementType: "IfcSlab", color: "rgba(0, 150, 255, 0.5)" },
//   { expressIds: [...], elementType: "IfcBeam", color: "rgba(0, 255, 0, 0.5)" }
// ]

const [walls, slabs, beams] = entities;
console.log(`Building has ${walls.expressIds.length} walls, ${slabs.expressIds.length} slabs, and ${beams.expressIds.length} beams`);
Implementation:
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)"
  );
  
  // Fallback to IFCWALLSTANDARDCASE if no walls found
  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;
Source: src/bim-components/ChartData/index.ts:97-110

chartData

Converts ChartData array into a Chart.js compatible dataset.
chartData = (data: ChartData[], chartType: string): BarDataset
Location: src/bim-components/ChartData/index.ts:112
data
ChartData[]
required
Array of ChartData objects to convert
chartType
string
required
Chart.js chart type (“bar”, “pie”, “doughnut”, “line”, etc.)
return
BarDataset
Chart.js compatible dataset ready for rendering
Example:
import Chart from "chart.js/auto";

const chartData = components.get(ChartData);

// Get element data
const entities = await chartData.getAllEntitiesOfType();

// Convert to chart dataset
const dataset = chartData.chartData(entities, "bar");

// Create chart
const ctx = document.getElementById('myChart') as HTMLCanvasElement;
const myChart = new Chart(ctx, dataset);

// The dataset structure:
// {
//   type: "bar",
//   data: {
//     labels: ["IfcWall", "IfcSlab", "IfcBeam"],
//     datasets: [{
//       label: "Quantity",
//       data: [150, 45, 30],
//       backgroundColor: ["rgba(255, 0, 0, 0.5)", "rgba(0, 150, 255, 0.5)", "rgba(0, 255, 0, 0.5)"],
//       borderWidth: [2, 2, 2],
//       borderRadius: [8, 8, 8],
//       borderColor: ["darkred", "darkblue", "darkgreen"]
//     }]
//   }
// }
Implementation:
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;
Source: src/bim-components/ChartData/index.ts:112-132

generateUniqueRGB

Internal utility method to generate unique random RGB colors.
generateUniqueRGB = (usedColors: Set<string>): string
Location: src/bim-components/ChartData/index.ts:38
usedColors
Set<string>
required
Set of already used color strings to ensure uniqueness
return
string
Unique RGB color string in format “rgb(r, g, b)“

Complete Usage Example

Building Analytics Dashboard

import * as OBC from "@thatopen/components";
import Chart from "chart.js/auto";
import { ChartData } from "./bim-components/ChartData";
import * as WEBIFC from "web-ifc";

// Initialize
const components = new OBC.Components();
const chartData = components.get(ChartData);

// Create bar chart of element types
async function createElementTypeChart() {
  const entities = await chartData.getAllEntitiesOfType();
  const dataset = chartData.chartData(entities, "bar");
  
  const ctx = document.getElementById('elementChart') as HTMLCanvasElement;
  new Chart(ctx, dataset);
}

// Create pie chart of elements per level
async function createLevelDistributionChart() {
  const levelData = await chartData.getPropertiesOfSpecificLevel();
  const dataset = chartData.chartData(levelData, "pie");
  
  const ctx = document.getElementById('levelChart') as HTMLCanvasElement;
  new Chart(ctx, dataset);
}

// Custom analysis: doors and windows
async function createOpeningsChart() {
  const doors = await chartData.getPropertiesOfSpecificType(
    WEBIFC.IFCDOOR,
    "Doors",
    "rgba(139, 69, 19, 0.5)"
  );
  
  const windows = await chartData.getPropertiesOfSpecificType(
    WEBIFC.IFCWINDOW,
    "Windows",
    "rgba(135, 206, 235, 0.5)"
  );
  
  const dataset = chartData.chartData([doors, windows], "doughnut");
  const ctx = document.getElementById('openingsChart') as HTMLCanvasElement;
  new Chart(ctx, dataset);
}

// Execute all charts
await createElementTypeChart();
await createLevelDistributionChart();
await createOpeningsChart();

Element Highlighting from Chart

import * as OBF from "@thatopen/components-front";

// Get chart data
const levelData = await chartData.getPropertiesOfSpecificLevel();
const dataset = chartData.chartData(levelData, "bar");

// Create interactive chart
const ctx = document.getElementById('myChart') as HTMLCanvasElement;
const myChart = new Chart(ctx, {
  ...dataset,
  options: {
    onClick: (event, elements) => {
      if (elements.length > 0) {
        const index = elements[0].index;
        const selectedLevel = levelData[index];
        
        // Highlight elements in 3D viewer
        const highlighter = components.get(OBF.Highlighter);
        const fragmentsManager = components.get(OBC.FragmentsManager);
        
        for (const [_, model] of fragmentsManager.groups) {
          highlighter.highlightByID(
            "select",
            selectedLevel.expressIds,
            true,
            false,
            model
          );
        }
      }
    }
  }
});

IFC Entity Types Reference

Commonly used types:
  • WEBIFC.IFCWALL - Wall elements
  • WEBIFC.IFCWALLSTANDARDCASE - Standard wall elements
  • WEBIFC.IFCSLAB - Floor/slab elements
  • WEBIFC.IFCBEAM - Beam elements
  • WEBIFC.IFCDOOR - Door elements
  • WEBIFC.IFCWINDOW - Window elements
  • WEBIFC.IFCBUILDINGSTOREY - Building levels/floors
  • WEBIFC.IFCCOLUMN - Column elements

Dependencies

  • @thatopen/components - Fragment and model management
  • @thatopen/ui - UI components
  • chart.js - Chart rendering library
  • web-ifc - IFC entity type definitions

Build docs developers (and LLMs) love