MaterialXWeb 0.0.2
Utilities for using MaterialX Packages with Web clients
Loading...
Searching...
No Matches
MaterialXGPUOpenClient.js
1import { WebSocketClient, WebSocketEventHandlers } from './WebSocketClient.js';
2
4{
5 constructor(socketLibrary, server) {
6 // Call parent to setup socket I/O.
7 super(socketLibrary, server);
8
9 this.editor = null;
10 this.extractedEditor = null;
11 this.materialsList = [];
12 this.materialNames = [];
13 this.materialCount = 0;
14
15 // Bind class methods to `this`
16 this.findMaterialByName = this.findMaterialByName.bind(this);
17 this.populateForm = this.populateForm.bind(this);
18 this.setupEventHandlers = this.setupEventHandlers.bind(this);
19 this.setupXML = this.setupXML.bind(this);
20
21 // Setup XML editors
22 this.setupXML();
23 }
24
25
26 findMaterialByName(name) {
27 let foundMaterial = null;
28
29 for (const element of this.materialsList) {
30 let resultsArray = JSON.parse(element).results;
31 if (resultsArray) {
32 for (const result of resultsArray) {
33 if (result.title === name) {
34 foundMaterial = result;
35 //console.log('>>>>>>>>>> Found Material:', result.title);
36 this.populateForm(result);
37 return foundMaterial;
38 }
39 }
40 }
41 }
42 return null; // Return null if no match is found
43 }
44
45 updateStatusInput(message, force = false)
46 {
47 const inputDOM = document.getElementById('status_message');
48 if (inputDOM.value == 'Status' || force)
49 inputDOM.value = message
50 else
51 inputDOM.value += '\n' + message
52 // Scroll to the bottom of the textarea
53 inputDOM.scrollTop = inputDOM.scrollHeight;
54 }
55
56 handleMaterialXDownLoad(data)
57 {
58 console.log('WEB: materialx downloaded event:', data);
59 this.materialCount = data.materialCount;
60 this.materialsList = data.materialsList;
61 this.materialNames = data.materialNames;
62
63 if (this.materialCount > 0) {
64 let listString = '';
65 for (const element of this.materialsList) {
66 listString += element + '\n';
67 }
68 this.editor.setValue(listString);
69
70 // Populate the material select dropdown
71 const materialSelect = document.getElementById('materialSelect');
72 materialSelect.innerHTML = ''; // Clear existing options
73 this.materialNames.forEach((name, index) => {
74 const option = document.createElement('option');
75 option.value = index + 1;
76 option.text = name;
77 materialSelect.appendChild(option);
78 });
79
80 // Populate the form with the first material
81 const firstMaterial = JSON.parse(this.materialsList[0]).results[0];
82 if (firstMaterial) {
83 this.populateForm(firstMaterial);
84 }
85 }
86 }
87
88 handleMaterialXExtract(data)
89 {
90 console.log('WEB: materialx extracted event:', data.extractedData);
91 const extractedData = data.extractedData[0];
92 const title = extractedData.title;
93 console.log('Title:', title);
94
95 const dataObj = extractedData.data;
96 const imageDOM = document.getElementById('extracted_images');
97 imageDOM.innerHTML = ''; // Clear existing images
98
99 const mtlxDOM = document.getElementById('extracted_mtlx');
100 this.extractedEditor.setValue('');
101
102 // Extract MTLX and images out.
103 // Optionally save zip of data to file.
104 let save_extracted = document.getElementById('save_extracted').checked;
105 let zip = save_extracted ? new JSZip() : null;
106 for (const key in dataObj) {
107 if (key.endsWith('.mtlx')) {
108 this.extractedEditor.setValue(dataObj[key]);
109 // Add the extracted MaterialX file to the zip
110 if (zip)
111 zip.file(key, dataObj[key]);
112 } else {
113 const base64String = dataObj[key];
114 const binary = atob(base64String);
115 const array = new Uint8Array(binary.length);
116 for (let i = 0; i < binary.length; i++) {
117 array[i] = binary.charCodeAt(i);
118 }
119 const extension = key.split('.').pop();
120 const blob = new Blob([array], { type: `image/${extension}` });
121 const url = URL.createObjectURL(blob);
122
123 // Create a container for the image and label
124 const imageContainer = document.createElement('div');
125 imageContainer.style.display = 'inline-block';
126 imageContainer.style.margin = '10px';
127 imageContainer.style.textAlign = 'center'; // Center the label under the image
128
129 // Create the image element
130 const img = document.createElement('img');
131 img.src = url;
132 img.width = 200;
133 img.alt = key;
134
135 // Add the key as a tooltip
136 img.title = key;
137
138 // Create a label for the image
139 const label = document.createElement('div');
140 label.innerText = key;
141 label.style.fontSize = '0.8rem';
142 //label.style.color = '#FFF'; //
143
144 // Append the image and label to the container
145 imageContainer.appendChild(img);
146 imageContainer.appendChild(label);
147
148 // Append the container to the image DOM
149 imageDOM.appendChild(imageContainer);
150
151 // Convert the blob to a file and add it to the zip
152 if (zip)
153 {
154 const imgFile = new File([blob], key, { type: 'image/${extension}' });
155 zip.file(key, imgFile);
156 }
157 }
158 }
159
160 // Create the zip file asynchronously
161 if (zip)
162 {
163 zip.generateAsync({ type: 'blob' }).then(function(content) {
164 // Create a download link for the zip file
165 const link = document.createElement('a');
166 link.href = URL.createObjectURL(content);
167 link.download = title + '.zip'; // Set the name of the zip file
168 link.click(); // Trigger the download
169 })
170 .catch(function(error) {
171 console.error('Error creating zip file:', error);
172 });
173 }
174 }
175
176 extractMaterials() {
177 const materialSelect = document.getElementById('materialSelect');
178 let selectedItem = materialSelect.options[materialSelect.selectedIndex].text;
179 console.log("WEB: Emitting extract_material event");
180 this.emit('extract_material', { expression: selectedItem });
181 }
182
183 downloadMaterials() {
184 console.log("WEB: Emitting download_materialx event");
185 this.emit('download_materialx', {});
186 }
187
188 setupEventHandlers() {
189 // Setup clear status button
190 document.getElementById('clear_status').addEventListener('click', () => {
191 this.updateStatusInput('Status', true);
192 });
193
194 // Bind "Extract Material" button click
195 document.getElementById('extract_material').addEventListener('click', () => {
196 this.extractMaterials();
197 });
198
199 // Bind "Download MaterialX" button click
200 document.getElementById('getMTLXButton').addEventListener('click', () => {
201 this.downloadMaterials();
202 });
203
204 // Set up socket message event handlers
205 this.webSocketWrapper = new WebSocketEventHandlers(this.socket, {
206 materialx_status: (data) => { console.log('WEB: materialx status event:', data.message); this.updateStatusInput(data.message) },
207 materialx_downloaded: (data) => { this.handleMaterialXDownLoad(data) },
208 materialx_extracted: (data) => { this.handleMaterialXExtract(data) }
209 });
210
211 // Update material selection
212 document.getElementById('materialSelect').addEventListener('change', () => {
213 const materialSelect = document.getElementById('materialSelect');
214 const selectedItem = materialSelect.options[materialSelect.selectedIndex].text;
215 this.findMaterialByName(selectedItem);
216 });
217 }
218
219 setupXML() {
220 // Initialize CodeMirror for MaterialX content
221 const materialXTextArea = document.getElementById('mtlxOutput');
222 this.editor = CodeMirror.fromTextArea(materialXTextArea, {
223 mode: 'application/json',
224 lineNumbers: true,
225 theme: 'dracula',
226 });
227 this.editor.setSize('auto', '300px');
228
229 // Initialize CodeMirror for extracted MaterialX content
230 const materialXTextArea2 = document.getElementById('extracted_mtlx');
231 this.extractedEditor = CodeMirror.fromTextArea(materialXTextArea2, {
232 mode: 'application/xml',
233 lineNumbers: true,
234 theme: 'dracula',
235 });
236 this.extractedEditor.setSize('auto', '300px');
237 }
238
239 populateForm(data) {
240 document.getElementById('m_title').value = data.title || '';
241 document.getElementById('author').value = data.author || '';
242 const pdate = data.published_date || '';
243 if (pdate) {
244 const date = new Date(pdate);
245 const offset = date.getTimezoneOffset();
246 const localDate = new Date(date.getTime() - offset * 60 * 1000);
247 const formattedDate = localDate.toISOString().slice(0, 16);
248 document.getElementById('published_date').value = formattedDate;
249 }
250 document.getElementById('mtlx_filename').value = data.mtlx_filename || '';
251 document.getElementById('category').value = data.category || '';
252 document.getElementById('status').value = data.status || 'Unpublished';
253 document.getElementById('tags').value = data.tags ? data.tags.join(', ') : '';
254 document.getElementById('packages').value = data.packages ? data.packages.join(', ') : '';
255 document.getElementById('renders').value = data.renders ? data.renders.join(', ') : '';
256 document.getElementById('description').value = data.description || '';
257 }
258}
259