Module @xeokit/data - v0.1.0

npm version

xeokit Semantic Data Model


The SDK's buildable, queryable, importable and exportable semantic data model


The xeokit SDK uses a generic entity-relationship data graph to manage model semantics. This graph includes entities, properties, and relationships and is compatible with both the browser and NodeJS. It serves as a versatile tool for generating models, converting between model formats, and navigating content within the model viewer.

In more detail, the xeokit SDK provides a Data container class that holds DataModels consisting of DataObjects, PropertySets, and Relationships, as shown in the diagram below.


Various model file formats can be imported into DataModels using methods such as @xeokit/gltf!loadGLTF, @xeokit/las!loadLAS, @xeokit/cityjson!loadCityJSON, and @xeokit/dtx!loadDTX, while DataModels can be exported to the native DTX format using @xeokit/dtx!saveDTX.

To programmatically build DataModels, builder methods such as Data.createModel, DataModel.createObject, DataModel.createPropertySet, and DataModel.createRelationship can be employed. DataObjects can be queried using the Data.searchObjects method, and semantic data can be attached to model representations by using it alongside SceneModel.

It's important to note that DataObjects and PropertySets are global, created on their DataModels but stored globally on the Data. Additionally, DataModels automatically reuse DataObjects and PropertySets wherever they're already created by other DataModels. Finally, DataObjects can have Relationships with other DataObjects in different DataModels.

Installation

npm install @xeokit/data

Usage

Creating a DataModel from JSON

We will start with an example where we create a @xeokit/data!DataModel using a single parameter object of type @xeokit/data!DataModelParams. The DataModel we create will define a simple piece of furniture - a table consisting of a tabletop and four legs. We will then query the data model to retrieve all the DataObjects within it.

To achieve this, we will create a DataModel that contains six DataObjects: one for the table, one for the tabletop, and one for each of the four legs. We will also define Relationships to connect the DataObjects into an aggregation hierarchy, and we will assign Properties to the DataObjects to give them attributes such as height and weight.

To give the DataObjects and Relationships semantic meaning, we will assign them types from one of the SDK's bundled data type sets, basicTypes. This set of types classifies each DataObject as a BasicEntity and each Relationship as a BasicAggregation.

It's worth noting that in a real-world scenario, we would likely use a more complex set of data types, such as @xeokit/ifctypes. However, we cannot mix different sets of data types within our @xeokit/data!Data, as traversals of the DataObjects with Data.searchObjects must be guided uniformly by the same set of types across all the DataObjects and Relationships in the graph.

To create our DataModel, we will use the following code, which creates a new Data object and then creates a DataModel from a set of objects, relationships, and property sets. The @xeokit/core!SDKError class is used to handle errors that may occur during the process:

import { SDKError } from "@xeokit/core";
import { Data } from "@xeokit/data";
import * as basicTypes from "@xeokit/basictypes/basicTypes";

const myData = new Data({});

const myDataModel = myData.createModel({
id: "myTableModel",
objects: [
{
id: "table",
type: basicTypes.BasicEntity,
name: "Table",
propertySetIds: ["tablePropertySet"],
},
{
id: "redLeg",
name: "Red table Leg",
type: basicTypes.BasicEntity,
propertySetIds: ["legPropertySet"],
},
{
id: "greenLeg",
name: "Green table leg",
type: basicTypes.BasicEntity,
propertySetIds: ["legPropertySet"],
},
{
id: "blueLeg",
name: "Blue table leg",
type: basicTypes.BasicEntity,
propertySetIds: ["legPropertySet"],
},
{
id: "yellowLeg",
name: "Yellow table leg",
type: basicTypes.BasicEntity,
propertySetIds: ["legPropertySet"],
},
{
id: "tableTop",
name: "Purple table top",
type: basicTypes.BasicEntity,
propertySetIds: ["tableTopPropertySet"],
},
],
relationships: [
{
type: basicTypes.BasicAggregation,
relatingObjectId: "table",
relatedObjectId: "tableTop",
},
{
type: basicTypes.BasicAggregation,
relatingObjectId: "tableTop",
relatedObjectId: "redLeg",
},
{
type: basicTypes.BasicAggregation,
relatingObjectId: "tableTop",
relatedObjectId: "greenLeg",
},
{
type: basicTypes.BasicAggregation,
relatingObjectId: "tableTop",
relatedObjectId: "blueLeg",
},
{
type: basicTypes.BasicAggregation,
relatingObjectId: "tableTop",
relatedObjectId: "yellowLeg",
},
],
propertySets: [
{
id: "tablePropertySet",
originalSystemId: "tablePropertySet",
name: "Table properties",
type: "",
properties: [
{
name: "Weight",
value: 5,
type: "",
valueType: "",
description: "Weight of the thing",
},
{
name: "Height",
value: 12,
type: "",
valueType: "",
description: "Height of the thing",
},
],
},
{
id: "legPropertySet",
originalSystemId: "legPropertySet",
name: "Table leg properties",
type: "",
properties: [
{
name: "Weight",
value: 5,
type: "",
valueType: "",
description: "Weight of the thing",
},
{
name: "Height",
value: 12,
type: "",
valueType: "",
description: "Height of the thing",
},
],
},
],
});

if (myDataModel instanceof SDKError) {
console.log(myDataModel.message);
} else {
myDataModel.build();
}

Creating a DataModel using Builder Methods

In our second example, we'll create our @xeokit/data!DataModel again, this time instantiating each @xeokit/data!PropertySet, Property, @xeokit/data!DataObject and @xeokit/data!Relationship individually, using the DataModel's builder methods.

import {SDKError} from "@xeokit/core";
import {Data} from "@xeokit/data";
import * as basicTypes from "@xeokit/basictypes/basicTypes";

const data = new Data();

const dataModel = data.createModel({ // DataModel | SDKError
id: "myTableModel"
});

if (dataModel instanceof SDKError) {
console.log(dataModel.message);

} else {

const tablePropertySet = dataModel.createPropertySet({ // PropertySet | SDKError
id: "tablePropertySet",
name: "Table properties",
type: "",
properties: [ // Property[]
{
name: "Weight",
value: 5,
type: "",
valueType: "",
description: "Weight of the thing"
},
{
name: "Height",
value: 12,
type: "",
valueType: "",
description: "Height of the thing"
}
]
});

if (tablePropertySet instanceof SDKError) {
console.log(tablePropertySet.message);
}

const legPropertySet = dataModel.createPropertySet({
id: "legPropertySet",
name: "Table leg properties",
type: "",
properties: [
{
name: "Weight",
value: 5,
type: "",
valueType: "",
description: "Weight of the thing"
},
{
name: "Height",
value: 12,
type: "",
valueType: "",
description: "Height of the thing"
}
]
});

const myTableObject = dataModel.createObject({ // DataObject | SDKError
id: "table",
type: basicTypes.BasicEntity,
name: "Table",
propertySetIds: ["tablePropertySet"]
});

if (myTableObject instanceof SDKError) {
console.log(myTableObject.message);
}

dataModel.createObject({
id: "redLeg",
name: "Red table Leg",
type: basicTypes.BasicEntity,
propertySetIds: ["tableLegPropertySet"]
});

dataModel.createObject({
id: "greenLeg",
name: "Green table leg",
type: basicTypes.BasicEntity,
propertySetIds: ["tableLegPropertySet"]
});

dataModel.createObject({
id: "blueLeg",
name: "Blue table leg",
type: basicTypes.BasicEntity,
propertySetIds: ["tableLegPropertySet"]
});

dataModel.createObject({
id: "yellowLeg",
name: "Yellow table leg",
type: "leg",
propertySetIds: ["tableLegPropertySet"]
});

dataModel.createObject({
id: "tableTop",
name: "Purple table top",
type: basicTypes.BasicEntity,
propertySetIds: ["tableTopPropertySet"]
});

const myRelationship = dataModel.createRelationship({
type: basicTypes.BasicAggregation,
relatingObjectId: "table",
relatedObjectId: "tableTop"
});

if (myRelationship instanceof SDKError) {
console.log(myRelationship.message);
}

dataModel.createRelationship({
type: basicTypes.BasicAggregation,
relatingObjectId: "tableTop",
relatedObjectId: "redLeg"
});

dataModel.createRelationship({
type: basicTypes.BasicAggregation,
relatingObjectId: "tableTop",
relatedObjectId: "greenLeg"
});

dataModel.createRelationship({
type: basicTypes.BasicAggregation,
relatingObjectId: "tableTop",
relatedObjectId: "blueLeg"
});

dataModel.createRelationship({
type: basicTypes.BasicAggregation,
relatingObjectId: "tableTop",
relatedObjectId: "yellowLeg"
});

dataModel.build()
.then(()=>{
// Ready for action
})
.catch((sdkError) => {
console.error(sdkError.message);
});
}

Reading DataObjects

With our @xeokit/scene!SceneModel built, we'll now use the @xeokit/data!Data.searchObjects method to traverse it to fetch the IDs of the DataObjects we find on that path.

One example of where we use this method is to query the aggregation hierarchy of the DataObjects for building a tree view of an IFC element hierarchy.

const resultObjectIds = [];

data.searchObjects({
startObjectId: "table",
includeObjects: [basicTypes.BasicEntity],
includeRelated: [basicTypes.BasicAggregation],
resultObjectIds
});

// resultObjectIds == ["table", "tableTop", "redLeg", "greenLeg", "blueLeg", "yellowLeg"];

Searching DataObjects

In our fourth example, we'll demonstrate how to traverse the DataObjects along their Relationships. We'll start at the root DataObject and visit all the DataObjects we encounter along the outgoing Relationships.

const table = data.objects["table"];

const relations = table.related[basicTypes.BasicAggregation];

for (let i = 0, len = relations.length; i < len; i++) {

const relation = relations[i];
const dataObject = relation.related;

//..
}

@xeokit/data

Index

Classes

Interfaces

Generated using TypeDoc