MaterialXLab API  0.0.1
APIs For MaterialXLab Libraries
Loading...
Searching...
No Matches
node_editor.js File Reference

Go to the source code of this file.

Classes

class  MxMaterialXMonitor
 Custom monitor class for MaterialX graph. More...
 

Functions

function toggleRequireUpdateUI ()
 
function export initializeNodeEditor (materialFilename, geometryId, customRenderer, user_icon_map=null, sampleFiles=null, readOnly=false)
 Function to initialize the MaterialX node editor.
 

Function Documentation

◆ initializeNodeEditor()

function export initializeNodeEditor ( materialFilename,
geometryId,
customRenderer,
user_icon_map = null,
sampleFiles = null,
readOnly = false )

Function to initialize the MaterialX node editor.

Parameters
materialFilename- The filename of the MaterialX document to load
geometryId- The id of the geometry to load
customRenderer- The custom renderer object to use for rendering
user_icon_map- The object containing the user icon map. Optional.
sampleFiles- The object containing the sample files. Optional.
readOnly- Flag to indicate if the editor is read-only. Optional.
Returns
{void}

Create a menu item for the library dropdown

Parameters
text- The text to display for the menu item
filename- The filename to load when the menu item is clicked
Returns
{HTMLElement} - The menu item element

Create a submenu for the library dropdown

Parameters
title- The title of the submenu
auto_close- Make the submenu appear if not top level
Returns
{HTMLElement} - The submenu element

Create the library menu structure

Parameters
sampleFiles- The object containing the library structure
libraryDropdown- The dropdown menu element
Returns
{void}

Display the node types in the UI

Parameters
nodeTypes- The object containing the node types
Returns
{void}

Update xml document text display

Parameters
contents- The contents of the document
Returns
{void}

Update gltf document text display

Parameters
contents- The contents of the document
Returns
{void}

Update javascript definitions display

Parameters
contents- The contents of the document
Returns
{void}

Add event handlers for UI elements

Returns
{void}

Definition at line 154 of file node_editor.js.

155 {
156 let my_icon_map = {
157 "_default_": "./Icons/materialx_logo.webp",
158 "_default_graph_": "./Icons/nodegraph_white.svg"
159 };
160
161 let geometryValues = ['teapot', 'shaderball', 'sphere', 'plane', 'cube', 'cylinder', 'donut', 'twist', '_loadFromFile_']
162
163 if (user_icon_map) {
164 // add items in user icon map. Overwrite any existing items
165 for (var key in user_icon_map) {
166 my_icon_map[key] = user_icon_map[key];
167 }
168 }
169
170 // Check if URI exists
171 function uriExists(uri) {
172 return fetch(uri)
173 .then(response => {
174 if (response.ok) {
175 return Promise.resolve(true);
176 } else {
177 return Promise.resolve(false);
178 }
179 })
180 .catch(error => {
181 console.log('Error checking URI:', error);
182 return Promise.resolve(false);
183 });
184 }
185
186 // Renderable item UI updater
187 function renderableItemUpdater(renderableItems) {
188 let renderableItemSelect = document.getElementById('renderableItem');
189 if (renderableItemSelect) {
190
191 const TRUNCATION_LENGTH = 12;
192
193 while (renderableItemSelect.firstChild) {
194 renderableItemSelect.removeChild(renderableItemSelect.firstChild);
195 }
196 for (let i = 0; i < renderableItems.length; i++) {
197 let item = renderableItems[i];
198 let option = document.createElement('option');
199 option.value = item;
200 let uiItem = item;
201 // Truncate the name so it will fit into UI.
202 if (uiItem.length > 20)
203 uiItem = uiItem.substring(0, 20) + '...';
204 option.text = uiItem;
205 renderableItemSelect.appendChild(option);
206 }
207 }
208 }
209
210 // Logger
211 // TODO: Pass in a logger object instead of looking for a DOM element.
212 function consoleLog(text, severity, clear = null) {
213 if (severity === 2) {
214 text = '> Error: ' + text
215 }
216 else if (severity === 1) {
217 text = '> Warning: ' + text
218 }
219 else {
220 if (text.length)
221 text = '> ' + text;
222 }
223
224 let console_area = document.getElementById('console_area');
225 if (console_area) {
226 if (clear) {
227 console_area.value = text + '\n';
228 }
229 else {
230 console_area.value = console_area.value + text + '\n';
231 }
232 // Scroll to latest entry.
233 console_area.scrollTop = console_area.scrollHeight;
234 }
235 else {
236 console.log(text);
237 }
238 }
239
240 /* function createMenuStructure(obj) {
241 let items = [];
242 for (let key in obj) {
243 if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
244 // It's a nested object, create a submenu
245 let subItems = createMenuStructure(obj[key]); // Recursively handle nested objects
246 items.push(createSubMenu(key, subItems));
247 } else {
248 items.push(createMenuItem(key, obj[key]));
249 }
250 console.log('<<< END SCAN');
251 }
252 return items;
253 } */
254
255
261
262 function createMenuItem(text, filename) {
263 let menuItem = document.createElement('li');
264 menuItem.className = 'dropdown-item';
265 menuItem.innerText = text;
266 menuItem.onclick = function () {
267 console.log('Load library file:', filename);
268 MxShadingGraphEditor.theEditor.handler.loadLibraryDocument(MxShadingGraphEditor.theEditor, filename);
269 // Collapse the dropdown menu
270 let dropdownMenu = document.getElementById('libraryDropdown');
271 dropdownMenu.classList.remove('show');
272 };
273 return menuItem;
274 }
275
281
282 function createSubMenu(title, auto_close = false) {
283
284 let li = document.createElement('li');
285 li.className = "dropend dropdown";
286 li.id = key;
287
288 let subMenu = document.createElement('a');
289 subMenu.className = "dropdown-item dropdown-toggle";
290 subMenu.setAttribute('data-bs-toggle', "dropdown");
291 if (auto_close) {
292 subMenu.setAttribute('data-bs-auto-close', 'outside');
293 }
294 subMenu.setAttribute('aria-expanded', 'false');
295 subMenu.setAttribute('aria-haspopup', 'true');
296 subMenu.innerHTML = title;
297 li.appendChild(subMenu);
298
299 return li;
300 }
301
307
308 function createLibraryMenu(sampleFiles, libraryDropdown) {
309 for (let key in sampleFiles) {
310 // Create top level menus
311 let li = createSubMenu(key, true);
312 libraryDropdown.appendChild(li);
313
314 let value = sampleFiles[key];
315
316 // Add items to the submenu
317 if (typeof value === 'string') {
318 let value = sampleFiles[key];
319 li.appendChild(createMenuItem(key, value));
320 }
321 else if (typeof value === 'object') {
322
323 let subMenuList = document.createElement('ul');
324 subMenuList.className = 'dropdown-menu';
325 subMenuList.id = key;
326
327 for (key in value) {
328
329 // Check if value is a string
330 if (typeof value[key] === 'string') {
331 subMenuList.appendChild(createMenuItem(key, value[key]));
332 }
333
334 else if (typeof value[key] === 'object') {
335
336 // Create sub level menus
337 let sli = createSubMenu(key, false);
338 subMenuList.appendChild(sli);
339
340 let ssubMenuList = document.createElement('ul');
341 ssubMenuList.className = 'dropdown-menu';
342 for (let skey in value[key]) {
343 ssubMenuList.appendChild(createMenuItem(skey, (value[key])[skey]));
344 }
345 sli.appendChild(ssubMenuList);
346 }
347 }
348
349 li.appendChild(subMenuList);
350 }
351
352 }
353 }
354
355 // Build material library menu UI
356 if (sampleFiles && libraryDropdown) {
357 createLibraryMenu(sampleFiles, libraryDropdown);
358 }
359
360 // Update selected geometry menu UI
361 let selectGeometryUI = false;
362 if (customRenderer) {
363
364 let geometryURL = geometryId;
365 if (geometryId.length > 0 && geometryValues.includes(geometryId)) {
366 geometryURL = 'Geometry/' + geometryId + '.glb';
367 selectGeometryUI = true;
368 }
369 var viewer = customRenderer.initialize(materialFilename, geometryURL, readOnly);
370 console.log('Setup renderer:', viewer);
371 }
372 else {
373 let preview_panel = document.getElementById("preview_panel");
374 // Hide preview_panel DOM element
375 if (preview_panel)
376 preview_panel.style.display = 'none';
377 }
378
379 // TODO: Pass in a ui function instead of looking for a DOM element.
384
385 function displayNodeTypes(nodeTypes) {
386 // Get the list container
387 var nodeList = document.getElementById('nodeTypesList');
388 if (!nodeList) {
389 return;
390 }
391
392 // Clear all children of nodeList
393 while (nodeList.firstChild) {
394 nodeList.removeChild(nodeList.firstChild);
395 }
396
397 // Iterate over the node types and add them to the list
398 for (var typeName in nodeTypes) {
399
400 var rowItem = document.createElement("tr");
401
402 var cellItem = document.createElement("td");
403 cellItem.textContent = typeName;
404 rowItem.appendChild(cellItem);
405
406 cellItem = document.createElement("td");
407 var nodeDefString = '<None>';
408 var nodeDefName = nodeTypes[typeName].nodedef_name;
409 var nodeDefNode = nodeTypes[typeName].nodedef_node
410 var nodeDefHref = nodeTypes[typeName].nodedef_href;
411 if (nodeDefName) {
412 if (nodeDefNode) {
413 var link = document.createElement("a");
414 link.target = "_blank";
415 link.href = nodeDefHref;
416 link.textContent = nodeDefNode + " ( " + nodeDefName + " )";
417 cellItem.appendChild(link);
418 }
419 else {
420 cellItem.textContent = nodeDefName;
421 }
422 }
423 else {
424 cellItem.textContent = nodeDefString;
425 }
426 rowItem.appendChild(cellItem);
427
428 nodeList.appendChild(rowItem);
429 }
430 }
431
432 // Set up syntax highlighting for text areas
433 var cmeditor = setupXMLSyntax();
434 var cmeditor2 = setupJavascriptSyntax();
435 var cmeditor3 = setupGLTFSyntax();
436
441
442 function docDisplayUpdater(contents) {
443 if (cmeditor)
444 cmeditor.setValue(contents);
445 }
446
451
452 function gltfDisplayUpdater(contents) {
453 if (!contents || contents.length == 0) {
454 contents = '{}';
455 }
456 if (cmeditor3)
457 cmeditor3.setValue(contents);
458 else
459 console.log(contents);
460 }
461
466
467 function jsDefinitionsDisplayUpdater(contents) {
468 if (cmeditor2)
469 cmeditor2.setValue(contents);
470 }
471
472 // Set up graphing UI
473 var canvas = document.getElementById('mygraphcanvas');
474 var ui = {
475 consoleLogger: consoleLog,
476 nodeTypesListUpdater: displayNodeTypes,
477 renderableItemUpdater: renderableItemUpdater,
478 documentDisplayUpdater: docDisplayUpdater,
479 gltfDocumentDisplayUpdater: gltfDisplayUpdater,
480 definitionsDisplayUpdater: jsDefinitionsDisplayUpdater,
481 propertypanel_content: document.getElementById('propertypanel_content'),
482 propertypanel_icon: document.getElementById('propertypanel_icon'),
483 icon_map: my_icon_map,
484 };
485 var editor = new MxShadingGraphEditor();
486
487 let monitor = new MxMaterialXMonitor('Custom MaterialX Graph Monitor');
488 monitor.setRenderer(customRenderer);
489 editor.initialize(canvas, ui, monitor, materialFilename, readOnly);
490
494
495 function addUIHandlers() {
496 // Add event listener to save canvas as image when button is clicked
497 var saveCanvasButton = document.getElementById('captureGraph');
498 if (saveCanvasButton) {
499 saveCanvasButton.addEventListener('click', function () {
500 var canvas = document.getElementById('mygraphcanvas');
501 var dataURL = canvas.toDataURL('image/png');
502 var link = document.createElement('a');
503 link.href = dataURL;
504 link.download = 'graph_capture.png';
505 link.click();
506 });
507 }
508
509 // TODO: Make this a user option
510 var auto_arrange_size = 80;
511
512 // Add load materialx graph event listener
513 var loadMaterialXDocumentFromFile = document.getElementById('loadMaterialXDocumentFromFile');
514 if (loadMaterialXDocumentFromFile) {
515 loadMaterialXDocumentFromFile.addEventListener('click', function () {
516 editor.loadGraphFromFile('mtlx', auto_arrange_size, true);
517 //toggleRequireUpdateUI();
518 });
519 }
520
521 // Add load materialx zip event listener
522 var loadMaterialXDocumentFromZip = document.getElementById('loadMaterialXDocumentFromZip');
523 if (loadMaterialXDocumentFromZip) {
524 loadMaterialXDocumentFromZip.addEventListener('click', function () {
525 editor.loadGraphFromFile('zip', auto_arrange_size, true);
526 //toggleRequireUpdateUI();
527 });
528 }
529
530 // Add load materialx graph from text event listener
531 var texAreaNumber = 0;
532 var loadMaterialXDocumentFromText = document.getElementById('loadMaterialXDocumentFromText');
533 if (loadMaterialXDocumentFromText) {
534 loadMaterialXDocumentFromText.addEventListener('click', function () {
535 var mtlxdoc = document.getElementById('mtlxdoc').value;
536 // Generate a name for the graph
537 if (mtlxdoc.length > 0) {
538 var name = 'MaterialXGraph' + texAreaNumber++;
539 editor.loadGraphFromString('mtlx', mtlxdoc, name, auto_arrange_size, true);
540 //toggleRequireUpdateUI();
541 }
542 });
543 }
544
545 // Add load definitions event listener
546 var loadMaterialXDefinitions = document.getElementById('loadMaterialXDefinitions');
547 if (loadMaterialXDefinitions) {
548 loadMaterialXDefinitions.addEventListener('click', function () {
549 editor.loadDefinitionsFromFile('mtlx');
550 });
551 }
552
553 // Add clear graph event listener
554 var clearGraphButton = document.getElementById('clearGraph');
555 if (clearGraphButton) {
556 clearGraphButton.addEventListener('click', function () {
557 editor.clearGraph();
559 });
560 }
561
562 // Add save materialx graph event listener
563 var saveMaterialXGraph = document.getElementById('saveMaterialXGraph');
564 if (saveMaterialXGraph) {
565 saveMaterialXGraph.addEventListener('click', function () {
566 var sl = document.getElementById('writeCustomLibs').checked;
567 var sp = document.getElementById('saveNodePositions').checked;
568 var wo = true;
569 var graphWriteOptions = { writeCustomLibs: sl, saveNodePositions: sp, writeOutputs: wo };
570 editor.saveGraphToFile('mtlx', graphWriteOptions);
571 });
572 }
573
574 // Add save materialx graph text event listener
575 var saveMaterialXGraphText = document.getElementById('saveMaterialXGraphText');
576 if (saveMaterialXGraphText) {
577 saveMaterialXGraphText.addEventListener('click', function () {
578 saveToStringUI();
579 });
580 }
581
582 // Search graph
583 var searchGraph = document.getElementById('searchGraph');
584 if (searchGraph) {
585 searchGraph.addEventListener('click', function () {
586 var search = document.getElementById('searchGraphText').value;
587 editor.searchGraph(search);
588 });
589 }
590
591 // Add open subgraph event handler
592 var openSubgraph = document.getElementById('openSubgraph');
593 if (openSubgraph) {
594 openSubgraph.addEventListener('click', function () {
595 editor.openSubgraph();
596 });
597 }
598
599 // Add close subgraph event handler
600 var closeSubgraph = document.getElementById('closeSubgraph');
601 if (closeSubgraph) {
602 closeSubgraph.addEventListener('click', function () {
603 editor.closeSubgraph();
604 });
605 }
606
607 // Add reset view event handler
608 var resetView = document.getElementById('resetView');
609 if (resetView) {
610 resetView.addEventListener('click', function () {
611 editor.resetView();
612 });
613 }
614
615 // Add arrange graph event listener
616 var arrangeGraphButton = document.getElementById('arrangeGraph');
617 if (arrangeGraphButton) {
618 arrangeGraphButton.addEventListener('click', function () {
619 editor.arrangeGraph();
620 });
621 }
622
623 // Add center node event listener
624 var centerNodeButton = document.getElementById('centerNode');
625 if (centerNodeButton) {
626 centerNodeButton.addEventListener('click', function () {
627 editor.centerNode();
628 });
629 }
630
631 // Add collapse/expand nodes event listener
632 var collapseNodesButton = document.getElementById('collapseNodes');
633 if (collapseNodesButton) {
634 collapseNodesButton.addEventListener('click', function () {
635 editor.collapseExpandNodes(true);
636 });
637 }
638 var expandNodesButton = document.getElementById('expandNodes');
639 if (expandNodesButton) {
640 expandNodesButton.addEventListener('click', function () {
641 editor.collapseExpandNodes(false);
642 });
643 }
644
645 // Add select all event listener
646 var selectNodesButton = document.getElementById('selectNodes');
647 if (selectNodesButton) {
648 selectNodesButton.addEventListener('click', function () {
649 editor.selectNodes();
650 });
651 }
652
653 // Add copy selected event listener
654 var copySelectedButton = document.getElementById('copySelected');
655 if (copySelectedButton) {
656 copySelectedButton.addEventListener('click', function () {
657 editor.copyToClipboard();
658 });
659 }
660
661 // Add paste selected event listener
662 var pasteSelectedButton = document.getElementById('pasteSelected');
663 if (pasteSelectedButton) {
664 pasteSelectedButton.addEventListener('click', function () {
665 editor.pasteFromClipboard();
666 });
667 }
668
669 // Add create subgraph event listener
670 var createNodeGraphButton = document.getElementById('createNodeGraph');
671 if (createNodeGraphButton) {
672 createNodeGraphButton.addEventListener('click', function () {
673 editor.createNodeGraph();
674 });
675 }
676
677 // Add extract subgraph event listener
678 var extractNodeGraphButton = document.getElementById('extractNodeGraph');
679 if (extractNodeGraphButton) {
680 extractNodeGraphButton.addEventListener('click', function () {
681 editor.extractNodeGraph();
682 });
683 }
684
685 /*
686 // Add load serialization event listener
687 var loadSerialization = document.getElementById('loadSerialization');
688 loadSerialization.addEventListener('click', function () {
689 editor.loadSerialization();
690 });
691
692 // Add download graph event listener
693 var downloadGraph = document.getElementById('downloadGraph');
694 downloadGraph.addEventListener('click', function () {
695 editor.saveSerialization();
696 }); */
697
698 // Add xml to graph event listener
699 var xmlToGraph = document.getElementById('xmltograph');
700 if (xmlToGraph) {
701 xmlToGraph.addEventListener('click', function () {
702 var name = 'MaterialXGraph' + texAreaNumber++;
703 var mtlxdoc = document.getElementById('mtlxdoc').value;
704 editor.loadGraphFromString('mtlx', mtlxdoc, 'MaterialXGraph', auto_arrange_size, true);
705 //toggleRequireUpdateUI();
706 });
707 }
708
709 function updateRenderableItemUI() {
710 let renderableItems = editor.findRenderableItems();
711 renderableItemUpdater(renderableItems);
712 }
713
714 function saveToStringUI() {
715 var cl = document.getElementById('writeCustomLibs').checked;
716 var sp = document.getElementById('saveNodePositions').checked;
717 var wo = true;
718 var graphWriteOptions = { writeCustomLibs: cl, saveNodePositions: sp, writeOutputs: wo };
719 console.log('Save with options: ', graphWriteOptions);
720 var result = editor.saveGraphToString('mtlx', graphWriteOptions);
721
722 cmeditor.setValue(result[0]);
723
724 if (customRenderer) {
725 customRenderer.setSourceColorSpace(editor.getSourceColorSpace());
726 customRenderer.setTargetDistanceUnit(editor.getTargetDistanceUnit());
727 customRenderer.updateMaterialFromText(result[0]);
728 updateRenderableItemUI();
729 }
730 }
731
732 // Add graph to xml event listener
733 var graphtoxml = document.getElementById('graphtoxml');
734 if (graphtoxml) {
735 graphtoxml.addEventListener('click', function () {
736 saveToStringUI();
737 });
738 }
739
740 let graphtoxml2 = document.getElementById('graphtoxml2');
741 if (graphtoxml2) {
742 graphtoxml2.addEventListener('click', function () {
743 saveToStringUI();
744 graphtoxml2.classList.remove('btn-outline-warning');
745 graphtoxml2.classList.add('btn-outline-secondary');
746 });
747 }
748
749 // Add graph to gltf event listener
750 var graphtogltf = document.getElementById('graphtogltf');
751 if (graphtogltf) {
752 graphtogltf.addEventListener('click', function () {
753 var graphWriteOptions = { writeCustomLibs: false, saveNodePositions: false, writeOutputs: true };
754 var result = editor.saveGraphToString('gltf', graphWriteOptions);
755 gltfDisplayUpdater(result[0]);
756 if (result[1]) {
757 consoleLog(result[1], 1, false);
758 }
759 });
760 }
761
762 // Add gltf to graph listener
763 var gltftograph = document.getElementById('gltftograph');
764 if (gltftograph) {
765 gltftograph.addEventListener('click', function () {
766 var gltfdoc = document.getElementById('gltfgraph').value;
767 if (gltfdoc.length > 0) {
768 editor.loadGraphFromString('gltf', gltfdoc, 'GLTFGraph', auto_arrange_size, true);
769 //toggleRequireUpdateUI();
770 }
771 });
772 }
773
774 // Handle turntable option
775 let turntableEnabledUI = document.getElementById('turntableEnabled');
776 if (turntableEnabledUI) {
777 turntableEnabledUI.addEventListener('click', (e) => {
778 // Toggle inverting the button colors no toggling danger
779 turntableEnabledUI.classList.toggle('btn-secondary');
780 if (customRenderer)
781 customRenderer.toggleTurntable();
782 });
783 }
784
785 // Handle render disabled option
786 let disableRenderingUI = document.getElementById('disableRendering');
787 if (disableRenderingUI) {
788 disableRenderingUI.addEventListener('click', (e) => {
789 // Toggle inverting the button colors
790 disableRenderingUI.classList.toggle('btn-danger');
791 if (customRenderer)
792 customRenderer.toggleRendering();
793 });
794 }
795
796 // Handle background display option
797 let toggleBackgroundTextureUI = document.getElementById('toggleBackgroundTexture');
798 if (toggleBackgroundTextureUI) {
799 toggleBackgroundTextureUI.addEventListener('click', (e) => {
800 toggleBackgroundTextureUI.classList.toggle('btn-primary');
801 if (customRenderer)
802 customRenderer.toggleBackgroundTexture();
803 });
804 }
805
806 // Handle reset camera option
807 let resetCameraUI = document.getElementById('resetCamera');
808 if (resetCameraUI) {
809 resetCameraUI.addEventListener('click', (e) => {
810 if (customRenderer) {
811 customRenderer.resetCamera();
812 }
813 });
814 }
815
816 // Handle renderable geometry option
817 function loadFromMenu(e) {
818 var uiItem = e.target.value;
819 if (uiItem == '_loadFromFile_') {
820 // Create a file dialog to get the filename
821 var fileInput = document.createElement('input');
822 fileInput.type = 'file';
823 fileInput.accept = '.glb';
824
825 fileInput.onchange = function(event) {
826 var file = event.target.files[0];
827 if (file) {
828 var fileURL = URL.createObjectURL(file);
829 if (customRenderer)
830 customRenderer.setRenderGeometry(fileURL);
831 console.log('Change geometry to:', fileURL, 'from file:', file.name);
832 }
833 }
834 fileInput.click();
835 }
836 else {
837 // Convert to lowercase and remove spaces
838 var geometryURL = uiItem.toLowerCase().replace(/\s/g, '');
839 var geometryPath = 'Geometry/' + geometryURL + '.glb';
840 console.log('Change geometry to:', geometryPath);
841 if (customRenderer)
842 customRenderer.setRenderGeometry(geometryPath);
843 }
844 }
845
846 // Handle geometry item changed
847 let geometryItemSelect = document.getElementById('loadGeometry');
848 if (geometryItemSelect) {
849
850 // Add built-in geometry options
851 var geometryItems = ['Teapot', 'Shader Ball', 'Sphere', 'Plane', 'Cube', 'Cylinder', 'Donut', 'Twist', 'Custom...'];
852 for (var i = 0; i < geometryItems.length; i++) {
853 var option = document.createElement('option');
854 option.value = geometryValues[i];
855 option.text = geometryItems[i];
856 geometryItemSelect.appendChild(option);
857 }
858
859 // Add event handler for selection
860 geometryItemSelect.addEventListener('change', (e) => {
861 loadFromMenu(e);
862 if (e.target.value == '_loadFromFile_')
863 e.target.value = 'Custom Geometry'
864 });
865
866 // Set initial geometry.
867 if (selectGeometryUI) {
868 // Set the default geometry
869 geometryItemSelect.value = geometryId;
870 }
871 }
872
873 // Handle material selection change
874 let renderableItemSelect = document.getElementById('renderableItem');
875 if (renderableItemSelect) {
876 renderableItemSelect.addEventListener('change', (e) => {
877 let index = e.target.value;
878 if (customRenderer)
879 {
880 customRenderer.setRenderMaterial(index);
881 editor.searchGraph(index);
882 }
883 });
884 }
885
886 // Get the canvas element and its container
887 var canvas = document.getElementById('mygraphcanvas');
888 var canvasContainer = document.getElementById('canvasContainer');
889 var colContainer = document.getElementById('colContainer');
890
891 // Create a new ResizeObserver
892 var observer = new ResizeObserver(function (entries) {
893 //for (var entry of entries) {
894 // Get the new width and height of the column
895 //let newWidth = entry.contentRect.right;
896 //let newHeight = entry.contentRect.height;
897
898 var parent = canvas.parentNode;
899 let newWidth = parent.offsetWidth;
900 let newHeight = parent.offsetHeight;
901
902 // Set the canvas size to match the column
903 //canvas.width = newWidth;
904 //canvas.height = newHeight;
905
906 // Mark the editor as dirty to redraw the graph.
907 console.log('Resize node graph canvas to:', newWidth, newHeight);
908 editor.setDirty(newWidth, newHeight);
909 //console.log('Resized node graph canvas to:', canvas.width, canvas.height);
910 //}
911 });
912
913 // Start observing the canvas container
914 observer.observe(canvasContainer);
915
916 }
917
918 function setupGLTFSyntax() {
919 // Initialize CodeMirror for GLTF syntax highlighting
920 let cmeditor = null;
921 const gltfTextArea = document.getElementById('gltfgraph');
922 if (gltfTextArea) {
923 cmeditor = CodeMirror.fromTextArea(gltfTextArea, {
924 mode: 'application/json',
925 lineNumbers: true,
926 dragDrop: false,
927 theme: 'dracula'
928 });
929
930 // Optional: Set an initial value for the textarea
931 const initialGLTF = '';
932 gltfTextArea.value = initialGLTF;
933 cmeditor.setValue(initialGLTF);
934
935 // Update CodeMirror whenever the textarea content changes
936 cmeditor.on('change', (e) => {
937 gltfTextArea.value = cmeditor.getValue();
938 });
939
940 var pasteButton = document.getElementById('gltfgraph_paste');
941 if (pasteButton)
942 addPasteHandler(pasteButton, cmeditor);
943
944 }
945 return cmeditor;
946 }
947
948 function setupJavascriptSyntax() {
949 // Initialize CodeMirror for JS syntax highlighting
950 const elem = document.getElementById('mtlxlib');
951 if (!elem) {
952 return;
953 }
954 let cmeditor = CodeMirror.fromTextArea(elem, {
955 mode: 'application/javascript',
956 lineNumbers: true,
957 dragDrop: false,
958 theme: 'dracula',
959 readOnly: true
960 });
961
962 elem.value = '';
963 cmeditor.setValue('');
964
965 // Update CodeMirror whenever the textarea content changes
966 cmeditor.on('change', () => {
967 elem.value = cmeditor.getValue();
968 });
969
970 return cmeditor;
971 }
972
973
974 function setupXMLSyntax() {
975 // Initialize CodeMirror for XML syntax highlighting
976 const materialXTextArea = document.getElementById('mtlxdoc');
977 let cmeditor = CodeMirror.fromTextArea(materialXTextArea, {
978 mode: 'application/xml',
979 lineNumbers: true,
980 dragDrop: true,
981 theme: 'night'
982 });
983
984 // Optional: Set an initial value for the textarea
985 const initialXML = '';
986 materialXTextArea.value = initialXML;
987 cmeditor.setValue(initialXML);
988
989 // Update CodeMirror whenever the textarea content changes
990 cmeditor.on('change', (e) => {
991 materialXTextArea.value = cmeditor.getValue();
992 });
993
994 var pasteButton = document.getElementById('mtlxdoc_paste');
995 if (pasteButton)
996 addPasteHandler(pasteButton, cmeditor);
997
998 return cmeditor;
999 }
1000
1001 addUIHandlers();
1002 addCopyHandlers();
1003}
Custom monitor class for MaterialX graph.
This class is a wrapper around the LiteGraph library to provide a MaterialX node editor.
function toggleRequireUpdateUI()

◆ toggleRequireUpdateUI()

function toggleRequireUpdateUI ( )

Definition at line 10 of file node_editor.js.

10 {
11 let graphtoxml2 = document.getElementById('graphtoxml2');
12 if (graphtoxml2) {
13 graphtoxml2.classList.remove('btn-outline-secondary');
14 graphtoxml2.classList.add('btn-outline-warning');
15 }
16}