Skip to content

Commit c127b87

Browse files
authored
✨ Previews: 2D images and 3D scenes (#4412)
1 parent f4931cb commit c127b87

File tree

13 files changed

+5173
-10
lines changed

13 files changed

+5173
-10
lines changed

services/static-webserver/client/source/class/osparc/Application.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ qx.Class.define("osparc.Application", {
6464
const intlTelInput = osparc.wrapper.IntlTelInput.getInstance();
6565
intlTelInput.init();
6666

67+
const threejs = osparc.wrapper.Three.getInstance();
68+
threejs.init();
69+
6770
const webSocket = osparc.wrapper.WebSocket.getInstance();
6871
webSocket.addListener("connect", () => osparc.io.WatchDog.getInstance().setOnline(true));
6972
webSocket.addListener("disconnect", () => osparc.io.WatchDog.getInstance().setOnline(false));

services/static-webserver/client/source/class/osparc/component/editor/ThumbnailSuggestions.js

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,9 @@ qx.Class.define("osparc.component.editor.ThumbnailSuggestions", {
7676
this.__thumbnailsPerNode[nodeId] = [];
7777
}
7878
this.__thumbnailsPerNode[nodeId].push({
79-
type: "image",
80-
source: srvMetadata["thumbnail"]
79+
type: "serviceImage",
80+
thumbnailUrl: srvMetadata["thumbnail"],
81+
fileUrl: srvMetadata["thumbnail"]
8182
});
8283
}
8384
});
@@ -87,12 +88,33 @@ qx.Class.define("osparc.component.editor.ThumbnailSuggestions", {
8788
// make it first in the list
8889
this.__thumbnailsPerNode["0000-workbenchUIPreview"] = [{
8990
type: "workbenchUIPreview",
90-
source: osparc.product.Utils.getWorkbenhUIPreviewPath()
91+
thumbnailUrl: osparc.product.Utils.getWorkbenhUIPreviewPath(),
92+
fileUrl: osparc.product.Utils.getWorkbenhUIPreviewPath()
9193
}];
9294
const themeManager = qx.theme.manager.Meta.getInstance();
9395
themeManager.addListener("changeTheme", () => this.addWorkbenchUIPreviewToSuggestions());
9496
},
9597

98+
addPreviewsToSuggestions: function(previewsPerNodes) {
99+
previewsPerNodes.forEach(previewsPerNode => {
100+
const nodeId = previewsPerNode["node_id"];
101+
const previews = previewsPerNode["screenshots"];
102+
if (previews && previews.length) {
103+
if (!(nodeId in this.__thumbnailsPerNode)) {
104+
this.__thumbnailsPerNode[nodeId] = [];
105+
}
106+
previews.forEach(preview => {
107+
this.__thumbnailsPerNode[nodeId].push({
108+
type: preview["mimetype"],
109+
thumbnailUrl: preview["thumbnail_url"],
110+
fileUrl: preview["file_url"]
111+
});
112+
});
113+
}
114+
});
115+
this.setSelectedNodeId(null);
116+
},
117+
96118
setSelectedNodeId: function(selectedNodeId) {
97119
let suggestions = new Set([]);
98120
if (selectedNodeId && selectedNodeId in this.__thumbnailsPerNode) {
@@ -111,14 +133,14 @@ qx.Class.define("osparc.component.editor.ThumbnailSuggestions", {
111133
this.removeAll();
112134
suggestions.forEach(suggestion => {
113135
const maxHeight = this.getMaxHeight();
114-
const thumbnail = new osparc.ui.basic.Thumbnail(suggestion.source, maxHeight, parseInt(maxHeight*2/3));
136+
const thumbnail = new osparc.ui.basic.Thumbnail(suggestion.thumbnailUrl, maxHeight, parseInt(maxHeight*2/3));
115137
thumbnail.setMarginLeft(1); // give some extra space to the selection border
116138
thumbnail.addListener("tap", () => {
117139
this.getChildren().forEach(thumbnailImg => osparc.utils.Utils.removeBorder(thumbnailImg));
118140
osparc.utils.Utils.addBorder(thumbnail, 1, "#007fd4"); // Visual Studio blue
119141
this.fireDataEvent("thumbnailTapped", {
120142
type: suggestion.type,
121-
source: suggestion.source
143+
source: suggestion.fileUrl
122144
});
123145
}, this);
124146
this.add(thumbnail);
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/* ************************************************************************
2+
3+
osparc - the simcore frontend
4+
5+
https://osparc.io
6+
7+
Copyright:
8+
2023 IT'IS Foundation, https://itis.swiss
9+
10+
License:
11+
MIT: https://opensource.org/licenses/MIT
12+
13+
Authors:
14+
* Odei Maiz (odeimaiz)
15+
16+
************************************************************************ */
17+
18+
qx.Class.define("osparc.component.widget.Three", {
19+
extend: qx.ui.core.Widget,
20+
21+
construct : function(fileUrl) {
22+
this.base(arguments);
23+
24+
this._setLayout(new qx.ui.layout.Canvas());
25+
26+
this.__transformControls = [];
27+
this.__entities = [];
28+
29+
this.addListenerOnce("appear", () => {
30+
this.__threeWrapper = osparc.wrapper.Three.getInstance();
31+
if (this.__threeWrapper.isLibReady()) {
32+
this.__start(fileUrl);
33+
} else {
34+
this.__threeWrapper.addListener("ThreeLibReady", e => {
35+
if (e.getData()) {
36+
this.__start(fileUrl);
37+
}
38+
});
39+
}
40+
}, this);
41+
},
42+
43+
members: {
44+
__threeWrapper: null,
45+
46+
__start: function(fileUrl) {
47+
this.getContentElement().getDomElement()
48+
.appendChild(this.__threeWrapper.getDomElement());
49+
50+
// this.__threeWrapper.SetCameraPosition(18, 0, 25);
51+
this.__threeWrapper.setCameraPosition(210, 210, 90); // Z up
52+
this.__threeWrapper.setBackgroundColor("#484f54");
53+
this.__resized();
54+
55+
this.addListener("resize", () => this.__resized(), this);
56+
57+
this.__render();
58+
59+
this.__threeWrapper.loadScene(fileUrl);
60+
},
61+
62+
__resized: function() {
63+
const minWidth = 400;
64+
const minHeight = 400;
65+
const bounds = this.getBounds();
66+
const width = Math.max(minWidth, bounds.width);
67+
const height = Math.max(minHeight, bounds.height);
68+
this.__threeWrapper.setSize(width, height);
69+
},
70+
71+
getThreeWrapper: function() {
72+
return this.__threeWrapper;
73+
},
74+
75+
__render: function() {
76+
this.__threeWrapper.render();
77+
},
78+
79+
addSnappingPlane: function(fixedAxe = 2, fixedPosition = 0) {
80+
let instersectionPlane = this.__threeWrapper.createInvisiblePlane(fixedAxe, fixedPosition);
81+
instersectionPlane.name = "PlaneForSnapping";
82+
this.__entities.push(instersectionPlane);
83+
},
84+
85+
removeSnappingPlane: function() {
86+
for (let i = 0; i < this.__entities.length; i++) {
87+
if (this.__entities[i].name === "PlaneForSnapping") {
88+
this.__entities.splice(i, 1);
89+
break;
90+
}
91+
}
92+
},
93+
94+
centerCameraToBB: function() {
95+
let center = {
96+
x: 0,
97+
y: 0,
98+
z: 0
99+
};
100+
if (this.__entities.length > 0) {
101+
let unionBBox = null;
102+
for (let i = 0; i < this.__entities.length; i++) {
103+
const ent = this.__entities[i];
104+
if (ent.Name === "PlaneForSnapping") {
105+
continue;
106+
}
107+
const bBox = this.__threeWrapper.getBBox(ent);
108+
if (unionBBox === null) {
109+
unionBBox = bBox;
110+
}
111+
unionBBox = this.__threeWrapper.mergeBBoxes(bBox, unionBBox);
112+
}
113+
center = this.__threeWrapper.getBBoxCenter(unionBBox);
114+
}
115+
this.__threeWrapper.setOrbitPoint(center);
116+
},
117+
118+
importGLTFSceneFromBuffer: function(modelBuffer) {
119+
this.__threeWrapper.importGLTFSceneFromBuffer(modelBuffer);
120+
}
121+
}
122+
});

services/static-webserver/client/source/class/osparc/dashboard/ResourceMoreOptions.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,16 @@ qx.Class.define("osparc.dashboard.ResourceMoreOptions", {
361361
return page;
362362
},
363363

364+
__getScenePage: function() {
365+
const id = "Scene";
366+
const title = this.tr("Scene");
367+
const icon = "https://avatars.githubusercontent.com/u/33161876?s=32";
368+
const threeView = new osparc.component.widget.Three("#00FF00");
369+
const page = this.__permissionsPage = this.__createPage(title, threeView, icon, id);
370+
page.setIcon(icon);
371+
return page;
372+
},
373+
364374
__getPermissionsPage: function() {
365375
const id = "Permissions";
366376
const resourceData = this.__resourceData;

services/static-webserver/client/source/class/osparc/dashboard/StudyThumbnailExplorer.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ qx.Class.define("osparc.dashboard.StudyThumbnailExplorer", {
107107
});
108108
thumbnailSuggestions.addWorkbenchUIPreviewToSuggestions();
109109
thumbnailSuggestions.setStudy(study);
110+
111+
const params = {
112+
url: {
113+
studyId: this.__studyData["uuid"]
114+
}
115+
};
116+
osparc.data.Resources.fetch("studyPreviews", "getPreviews", params)
117+
.then(previewsPerNodes => thumbnailSuggestions.addPreviewsToSuggestions(previewsPerNodes))
118+
.catch(err => console.error(err));
119+
110120
return thumbnailSuggestions;
111121
},
112122

@@ -128,12 +138,15 @@ qx.Class.define("osparc.dashboard.StudyThumbnailExplorer", {
128138
const thumbnailData = e.getData();
129139
let control = null;
130140
switch (thumbnailData["type"]) {
131-
case "image":
132-
control = this.__getThumbnail(thumbnailData["source"]);
133-
break;
134141
case "workbenchUIPreview":
135142
control = this.__getWorkbenchUIPreview();
136143
break;
144+
case null:
145+
control = this.__getThreeSceneViewer(thumbnailData["source"]);
146+
break;
147+
default:
148+
control = this.__getThumbnail(thumbnailData["source"]);
149+
break;
137150
}
138151
if (control) {
139152
thumbnailViewerLayout.removeAll();
@@ -171,6 +184,11 @@ qx.Class.define("osparc.dashboard.StudyThumbnailExplorer", {
171184
return workbenchUIPreview;
172185
},
173186

187+
__getThreeSceneViewer: function(fileUrl) {
188+
const threeView = new osparc.component.widget.Three(fileUrl);
189+
return threeView;
190+
},
191+
174192
__initComponents: function() {
175193
const scrollThumbnails = this.getChildControl("scroll-thumbnails");
176194
scrollThumbnails.setSelectedNodeId(null);

services/static-webserver/client/source/class/osparc/data/Resources.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,16 @@ qx.Class.define("osparc.data.Resources", {
199199
}
200200
}
201201
},
202+
"studyPreviews": {
203+
useCache: true,
204+
idField: "uuid",
205+
endpoints: {
206+
getPreviews: {
207+
method: "GET",
208+
url: statics.API + "/projects/{studyId}/nodes/-/preview"
209+
}
210+
}
211+
},
202212
/*
203213
* NODES
204214
*/

services/static-webserver/client/source/class/osparc/info/CardLarge.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ qx.Class.define("osparc.info.CardLarge", {
5757
members: {
5858
_attachHandlers: function() {
5959
this.addListenerOnce("appear", () => this._rebuildLayout(), this);
60-
this.addListener("resize", () => this._rebuildLayout(), this);
60+
// OM: Not so sure about this one
61+
// this.addListener("resize", () => this._rebuildLayout(), this);
6162
},
6263

6364
_rebuildLayout: function() {

services/static-webserver/client/source/class/osparc/product/Utils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ qx.Class.define("osparc.product.Utils", {
145145
},
146146

147147
showStudyPreview: function() {
148-
if (this.isProduct("osparc") || this.isProduct("s4l")) {
148+
if (this.isProduct("osparc") || this.isProduct("s4l") || this.isProduct("s4llite")) {
149149
return true;
150150
}
151151
return false;

services/static-webserver/client/source/class/osparc/store/Store.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ qx.Class.define("osparc.store.Store", {
6666
check: "Array",
6767
init: []
6868
},
69+
studyPreviews: {
70+
check: "Array",
71+
init: []
72+
},
6973
nodesInStudyResources: {
7074
check: "Array",
7175
init: []

0 commit comments

Comments
 (0)