Property Editing¶
IFClite supports editing IFC properties in-place with full change tracking, undo/redo, and export. The @ifc-lite/mutations package provides the mutation infrastructure, while the viewer integrates it with a property editor UI.
How It Works¶
Mutations are tracked through a MutablePropertyView that wraps the original read-only property table. When you edit a property:
- The original value is preserved
- The new value is stored in an overlay
- Reads return the mutated value transparently
- All changes are tracked as a
Mutationwith old/new values - Changes can be exported, applied to other models, and shared via change sets
Quick Start¶
Editing Properties¶
import { MutablePropertyView } from '@ifc-lite/mutations';
// Create a mutable view over the property table
// Parameters: (baseTable: PropertyTable | null, modelId: string)
const view = new MutablePropertyView(propertyTable, 'my-model');
// Set a property value
const mutation = view.setProperty(
entityId, // Express ID of the entity
'Pset_WallCommon', // Property set name
'FireRating', // Property name
'REI 120', // New value
);
console.log(`Changed from "${mutation.oldValue}" to "${mutation.newValue}"`);
// Read the mutated value
const value = view.getPropertyValue(entityId, 'Pset_WallCommon', 'FireRating');
// Returns 'REI 120'
Mutation History¶
// Get all mutations applied to this view
const mutations = view.getMutations();
// Check if an entity has changes
const hasChanges = view.hasChanges(entityId);
// Get count of modified entities
const count = view.getModifiedEntityCount();
// Clear all mutations (reset to original state)
view.clear();
Note: Undo/redo is handled by the viewer's store (mutationSlice), not directly on MutablePropertyView. In the viewer, use Ctrl+Z / Ctrl+Shift+Z.
Change Sets¶
Change sets group related mutations for export and sharing:
import { ChangeSetManager } from '@ifc-lite/mutations';
const manager = new ChangeSetManager();
// Create a change set (becomes the active change set)
const changeSet = manager.createChangeSet('Fire Safety Updates');
// Add mutations to the active change set
manager.addMutation(mutation1);
manager.addMutation(mutation2);
// Export as JSON
const json = manager.exportChangeSet(changeSet.id);
// Import on another instance
const imported = manager.importChangeSet(json);
Bulk Operations¶
For updating many entities at once, use the BulkQueryEngine:
import { BulkQueryEngine } from '@ifc-lite/mutations';
import { PropertyValueType } from '@ifc-lite/data';
// Constructor requires EntityTable and MutablePropertyView
const engine = new BulkQueryEngine(entityTable, mutationView);
// Define a bulk query - which entities to update and how
const query = {
select: {
entityTypes: [10], // Type enum values (e.g., IfcWall)
propertyFilters: [{
psetName: 'Pset_WallCommon',
propName: 'IsExternal',
operator: '=' as const,
value: true,
}],
},
action: {
type: 'SET_PROPERTY' as const,
psetName: 'Pset_WallCommon',
propName: 'ThermalTransmittance',
value: 0.18,
valueType: PropertyValueType.Real,
},
};
// Preview changes before applying
const preview = engine.preview(query);
console.log(`Will update ${preview.matchedCount} entities`);
// Apply
const result = engine.execute(query);
console.log(`Updated ${result.affectedEntityCount} properties`);
CSV Import¶
Import property updates from spreadsheets:
import { CsvConnector } from '@ifc-lite/mutations';
import { PropertyValueType } from '@ifc-lite/data';
// Constructor requires EntityTable and MutablePropertyView
const connector = new CsvConnector(entityTable, mutationView);
// Parse CSV (returns CsvRow[])
const rows = connector.parse(csvString, {
delimiter: ',',
hasHeader: true,
});
// Define mapping from CSV columns to IFC properties
const mapping = {
matchStrategy: { type: 'globalId' as const, column: 'GlobalId' },
propertyMappings: [
{ sourceColumn: 'Fire Rating', targetPset: 'Pset_WallCommon', targetProperty: 'FireRating', valueType: PropertyValueType.String },
{ sourceColumn: 'U-Value', targetPset: 'Pset_WallCommon', targetProperty: 'ThermalTransmittance', valueType: PropertyValueType.Real },
],
};
// Import (takes CSV string directly, not pre-parsed rows)
const stats = connector.import(csvString, mapping);
console.log(`Matched: ${stats.matchedRows}, Updated: ${stats.mutationsCreated}, Skipped: ${stats.unmatchedRows}`);
Viewer Integration¶
In the IFClite viewer:
- Select an entity in 3D or the hierarchy panel
- Open Properties panel - Edit properties directly in the panel
- Bulk edit - Use the Property Editor to update multiple entities
- Track changes - Modified properties are highlighted
- Undo/Redo - Ctrl+Z / Ctrl+Shift+Z to undo/redo edits
- Export - Save modified IFC with changes applied
Mutation State¶
| State | Description |
|---|---|
| Modified entities | Count of entities with property changes |
| Dirty models | Models with unsaved mutations |
| Undo stack | Per-model undo history |
| Redo stack | Per-model redo history |
| Change sets | Named groups of mutations for export |
Key Types¶
| Type | Description |
|---|---|
MutablePropertyView |
Wraps property table with mutation overlay |
Mutation |
A single property change with old/new values |
ChangeSet |
Named collection of mutations |
ChangeSetManager |
Manages multiple change sets |
BulkQueryEngine |
Query and update entities in bulk |
CsvConnector |
Import property data from CSV files |