Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit 42d2a66

Browse files
Added support for .obj model type.
1 parent 8df56e6 commit 42d2a66

6 files changed

+169
-90
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# 3D Model Viewer Widget for Cumulocity IoT
22

3-
This is a runtime widget to view a 3D collada model (*.dae) in Cumulocity IoT.
3+
This is a runtime widget to view a 3D collada model (*.dae, *.obj) in Cumulocity IoT.
44

55
<img src="/assets/img-preview.png" />
66

77
### Features
88
* Supports measurements from a single device
99
* Allows background color customization.
1010
* Allows to configure realtime device measurement for model movements.
11-
* Allows to upload custom collada(.dae) model file.
11+
* Allows to upload custom collada(.dae, .obj) model file.
1212

1313
### Installation - for the dashboards using Runtime Widget Loader
1414
1. Download the latest `3d-model-viewer-widget-{version}.zip` file from the Releases section.
@@ -23,7 +23,7 @@ This is a runtime widget to view a 3D collada model (*.dae) in Cumulocity IoT.
2323
3. Choose `3d model viewer` widget.
2424
4. `Title` is the title of widget. Provide a relevant name. You may choose to hide this. Go to `Appearance` tab and choose `Hidden` under `Widget header style`.
2525
5. Select the `device`.
26-
6. `Model file(*.dae)` is to upload the model file (*.dae) into inventory binary. Please wait for it to finish the upload.
26+
6. `Model file(*.dae, *.obj)` is to upload the model file (*.dae, *.obj) into inventory binary. Please wait for it to finish the upload.
2727
7. `Variables` is to declare variables with a constant value or map them to the realtime device measurement series. Choose Target as None and provide the constant value or choose Target as Device and then select a measurment series.
2828
8. `Properties` is to define values for the model properties. You can provide a value as an mathematical expression using the variables defined earlier.
2929
9. `Background color (in hex)` allows you to set a custom background color using the color picker.

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"dist\\bundle-src\\custom-widget.js": "3d-model-viewer-widget-CustomWidget",
55
"dist/bundle-src/custom-widget.js": "3d-model-viewer-widget-CustomWidget"
66
},
7-
"version": "1.0.1",
7+
"version": "2.0.0",
88
"description": "",
99
"main": "index.js",
1010
"scripts": {

src/model-viewer-widget/model-viewer-widget-config.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
<c8y-form-group>
33

44
<!-- Model File -->
5-
<label for="model-file" translate>Model file (*.dae)</label>
5+
<label for="model-file" translate>Model file (*.dae, *.obj)</label>
66
<input type="text" class="form-control" [(ngModel)]="widgetInfo.binaryName" readonly />
7-
<input type="file" class="form-control" name="model-file" (change)="uploadModelFile($event.target.files)" accept=".dae,model/vnd.collada+xml" />
7+
<input type="file" class="form-control" name="model-file" (change)="uploadModelFile($event.target.files)" accept=".dae,model/vnd.collada+xml,.obj" />
88
<div>{{modelFileUploadMessage}}</div>
99

1010
<!-- Separator -->

src/model-viewer-widget/model-viewer-widget-config.component.ts

Lines changed: 52 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
*/
1818

1919
import { Component, Input, OnInit } from '@angular/core';
20-
import { jsonpFactory } from '@angular/http/src/http_module';
2120
import { IResult, IFetchOptions } from '@c8y/client/lib/src/core';
2221
import { IManagedObjectBinary } from '@c8y/client/lib/src/inventory';
2322
import { FetchClient, InventoryBinaryService } from '@c8y/ngx-components/api';
@@ -36,7 +35,6 @@ export class ModelViewerWidgetConfig implements OnInit {
3635

3736
modelFile: File = null;
3837
modelFileUploadMessage: string;
39-
private measurementSeriesLoaded: boolean = false;
4038
public measurementSeries = [];
4139
public variableTargets = [
4240
{
@@ -52,6 +50,7 @@ export class ModelViewerWidgetConfig implements OnInit {
5250
widgetInfo = {
5351
binaryId: '',
5452
binaryName: '',
53+
modelType: '',
5554
advanced: {
5655
backgroundColor: '#6d82a3',
5756
showGrid: 'true'
@@ -152,25 +151,25 @@ export class ModelViewerWidgetConfig implements OnInit {
152151
if(_.has(this.config, 'device.id') && this.config.device.id !== undefined && this.config.device.id !== null && this.config.device.id !== '') {
153152
this.loadMeasurementSeries();
154153
} else {
155-
console.log("Device is not selected. Select a device.");
154+
console.log("3D Model Viewer Widget - Device is not selected. Select a device.");
156155
}
157156
if(_.has(this.widgetInfo, 'binaryId') && this.widgetInfo.binaryId !== undefined && this.widgetInfo.binaryId !== null && this.widgetInfo.binaryId !== '') {
158157
this.loadInfoFromModel();
159158
} else {
160-
console.log("Binary ID is blank. Upload model file.");
159+
console.log("3D Model Viewer Widget - Binary ID is blank. Upload model file.");
161160
}
162161
} else { // Adding a new widget
163162
_.set(this.config, 'customwidgetdata', this.widgetInfo);
164163
}
165164
} catch(e) {
166-
console.log("Exception: "+e);
165+
console.log("3D Model Viewer Widget - Exception: "+e);
167166
}
168167

169168
}
170169

171170
public uploadModelFile(files: FileList) {
172171
if(files === undefined || files === null || files.length < 1) {
173-
console.log("No file selected.");
172+
console.log("3D Model Viewer Widget - No file selected.");
174173
} else {
175174
this.modelFileUploadMessage = 'Uploading...';
176175
this.modelFile = files.item(0);
@@ -179,74 +178,73 @@ export class ModelViewerWidgetConfig implements OnInit {
179178
if(data.res.status === 201) {
180179
this.widgetInfo.binaryId = data.data.id;
181180
this.widgetInfo.binaryName = this.modelFile.name;
181+
this.widgetInfo.modelType = this.widgetInfo.binaryName.substring(this.widgetInfo.binaryName.lastIndexOf(".")).toLowerCase();
182182
this.modelFileUploadMessage = 'Upload success!';
183183
this.updateConfig();
184184
this.loadInfoFromModel();
185185
} else {
186186
this.modelFileUploadMessage = 'Upload failed!';
187-
console.log("Model cannot be uploaded: "+data.res.status);
187+
console.log("3D Model Viewer Widget - Model cannot be uploaded: "+data.res.status);
188188
}
189189
});
190190
}
191191
}
192192

193193
public loadMeasurementSeries() {
194194
if(!_.has(this.config, 'device.id') || this.config.device.id === undefined || this.config.device.id === "") {
195-
console.log("Device is not selected.");
195+
console.log("3D Model Viewer Widget - Device is not selected.");
196196
} else {
197-
if(!this.measurementSeriesLoaded) {
198-
const options: IFetchOptions = {
199-
method: 'GET'
200-
};
201-
let supportedSeriesResponse = this.fetchClient.fetch('/inventory/managedObjects/'+this.config.device.id+'/supportedSeries', options);
202-
let me = this;
203-
supportedSeriesResponse.then((data) => {
204-
data.json().then((res: any) => {
205-
res.c8y_SupportedSeries.forEach((ss) => {
206-
me.measurementSeries.push(ss);
207-
});
208-
me.measurementSeriesLoaded = true;
197+
this.measurementSeries = [];
198+
const options: IFetchOptions = {
199+
method: 'GET'
200+
};
201+
let supportedSeriesResponse = this.fetchClient.fetch('/inventory/managedObjects/'+this.config.device.id+'/supportedSeries', options);
202+
let me = this;
203+
supportedSeriesResponse.then((data) => {
204+
data.json().then((res: any) => {
205+
res.c8y_SupportedSeries.forEach((ss) => {
206+
me.measurementSeries.push(ss);
209207
});
210208
});
211-
} else {
212-
console.log("Measurement series already loaded: "+JSON.stringify(this.measurementSeries));
213-
}
209+
});
214210
}
215211
}
216212

217213
private loadInfoFromModel() {
218-
const options: IFetchOptions = {
219-
method: 'GET'
220-
};
221-
let res = this.fetchClient.fetch('/inventory/binaries/'+this.widgetInfo.binaryId, options);
222-
res.then((data) => {
223-
data.text().then((modelData) => {
224-
const loader = new ColladaLoader();
225-
let modelUrl = URL.createObjectURL(new Blob([modelData]));
226-
const me = this;
227-
loader.load(modelUrl, function(collada) {
228-
if(collada.kinematics && collada.kinematics.joints) {
229-
const keys = Object.keys(collada.kinematics.joints);
230-
let kinematics = {
231-
type: 'Kinematics',
232-
values: []
233-
}
234-
keys.forEach(k => {
235-
const joint = collada.kinematics.joints[k];
236-
if(!joint.static) {
237-
kinematics.values.push({
238-
name: k,
239-
min: joint.limits.min,
240-
max: joint.limits.max,
241-
defaultValue: joint.zeroPosition
242-
});
214+
if(this.widgetInfo.modelType === ".dae") {
215+
const options: IFetchOptions = {
216+
method: 'GET'
217+
};
218+
let res = this.fetchClient.fetch('/inventory/binaries/'+this.widgetInfo.binaryId, options);
219+
res.then((data) => {
220+
data.text().then((modelData) => {
221+
const loader = new ColladaLoader();
222+
let modelUrl = URL.createObjectURL(new Blob([modelData]));
223+
const me = this;
224+
loader.load(modelUrl, function(collada) {
225+
if(collada.kinematics && collada.kinematics.joints) {
226+
const keys = Object.keys(collada.kinematics.joints);
227+
let kinematics = {
228+
type: 'Kinematics',
229+
values: []
243230
}
244-
})
245-
me.modelProperties.push(kinematics);
246-
}
247-
});
248-
})
249-
});
231+
keys.forEach(k => {
232+
const joint = collada.kinematics.joints[k];
233+
if(!joint.static) {
234+
kinematics.values.push({
235+
name: k,
236+
min: joint.limits.min,
237+
max: joint.limits.max,
238+
defaultValue: joint.zeroPosition
239+
});
240+
}
241+
})
242+
me.modelProperties.push(kinematics);
243+
}
244+
});
245+
})
246+
});
247+
}
250248
}
251249

252250
public addVariable(): void {

0 commit comments

Comments
 (0)