MaterialXLab API  0.0.1
APIs For MaterialXLab Libraries
Loading...
Searching...
No Matches
JsMaterialXGraph.js
Go to the documentation of this file.
1
7{
13 this.doc = doc;
14 this.graphDictionary = {};
15 this.connections = [];
16 this.includeGraphs = '';
17 }
18
25 this.includeGraphs = graphs;
26 }
27
33 return this.graphDictionary;
34 }
35
41 return this.connections;
42 }
43
54 updateGraphDictionaryPath(key, item, nodetype, type, value, graphDictionary) {
55 if (key in graphDictionary) {
56 graphDictionary[key].push([item, nodetype, type, value]);
57 } else {
58 graphDictionary[key] = [[item, nodetype, type, value]];
59 }
60 }
61
68 updateGraphDictionaryItem(item, graphDictionary) {
69 if (!item) return;
70
71 let parentElem = item.getParent();
72 if (!parentElem || !(parentElem instanceof mx.GraphElement)) return;
73
74 let key = parentElem.getNamePath();
75 let value = item.getNamePath();
76 let itemType = item.getType();
77 let itemCategory = item.getCategory();
78 let itemValue = '';
79
80 if (item instanceof mx.Node) {
81 let inputs = item.getInputs();
82 if (inputs.length === 1) {
83 itemValue = inputs[0].getValueString();
84 }
85 } else if (item instanceof mx.Input) {
86 itemValue = item.getValueString();
87 }
88
89 this.updateGraphDictionaryPath(key, value, itemCategory, itemType, itemValue, graphDictionary);
90 }
91
97 printGraphDictionary(graphDictionary) {
98 for (let graphPath in graphDictionary) {
99 if (graphPath === '') {
100 console.log('Root Document:');
101 } else {
102 console.log(graphPath + ':');
103 }
104
105 let filter = 'input';
106 for (let item of graphDictionary[graphPath]) {
107 if (item[1] !== filter) continue;
108 console.log('- ', item);
109 }
110
111 filter = 'output';
112 for (let item of graphDictionary[graphPath]) {
113 if (item[1] !== filter) continue;
114 console.log('- ', item);
115 }
116
117 filter = ['output', 'input'];
118 for (let item of graphDictionary[graphPath]) {
119 if (!filter.includes(item[1])) {
120 console.log('- ', item);
121 }
122 }
123 }
124 }
125
132 while (elem && !(elem instanceof mx.GraphElement)) {
133 elem = elem.getParent();
134 }
135 return elem;
136 }
137
144 if (!node) return '';
145
146 let defaultOutput = null;
147 if (node instanceof mx.Node) {
148 let nodedef = node.getNodeDef();
149 if (nodedef) {
150 defaultOutput = nodedef.getActiveOutputs()[0];
151 } else {
152 console.log('Cannot find nodedef for node:', node.getNamePath());
153 }
154 } else if (node instanceof mx.NodeGraph) {
155 defaultOutput = node.getOutputs()[0];
156 }
157
158 return defaultOutput ? defaultOutput.getName() : '';
159 }
160
167 appendPath(p1, p2) {
168 return p2 ? p1 + '/' + p2 : p1;
169 }
170
179 buildPortConnection(doc, portPath, connections, portIsNode) {
180 let root = doc.getDocument();
181 let port = root.getDescendant(portPath);
182 if (!port) {
183 console.log('Element not found:', portPath);
184 return;
185 }
186
187 if (!(port instanceof mx.Input) && !(port instanceof mx.Output)) {
188 console.log('Element is not an input or output');
189 return;
190 }
191
192 let parent = port.getParent();
193 let parentPath = parent.getNamePath();
194 let parentGraph = this.getParentGraph(port);
195
196 if ((port instanceof mx.Input) && (parent instanceof mx.NodeGraph)) {
197 parentGraph = parentGraph.getParent();
198 }
199
200 if (!parentGraph) {
201 console.log('Cannot find parent graph of port', port);
202 //return;
203 }
204 let parentGraphPath = parentGraph.getNamePath();
205
206 let outputName = port.getOutputString();
207
208 let destNode = portIsNode ? portPath : parentPath;
209 let destPort = portIsNode ? '' : port.getName();
210
211 let nodename = port.getAttribute('nodename');
212 if (nodename) {
213 let result;
214 if (!parentGraphPath) {
215 result = [this.appendPath(nodename, ''), outputName, destNode, destPort, 'nodename'];
216 } else {
217 result = [this.appendPath(parentGraphPath, nodename), outputName, destNode, destPort, 'nodename'];
218 }
219 connections.push(result);
220 return;
221 }
222
223 let nodegraph = port.getNodeGraphString();
224 if (nodegraph) {
225 if (!outputName) {
226 outputName = this.getDefaultOutput(parentGraph.getChild(nodegraph));
227 }
228 let result;
229 if (!parentGraphPath) {
230 result = [this.appendPath(nodegraph, outputName), '', destNode, destPort, 'nodename'];
231 } else {
232 result = [this.appendPath(parentGraphPath, nodegraph), outputName, destNode, destPort, 'nodegraph'];
233 }
234 connections.push(result);
235 return;
236 }
237
238 let interfaceName = port.getInterfaceName();
239 if (interfaceName) {
240 let result;
241 if (!parentGraphPath) {
242 if (!outputName) {
243 outputName = this.getDefaultOutput(parentGraph.getChild(interfaceName));
244 }
245 result = [this.appendPath(interfaceName, outputName), '', destNode, destPort, 'nodename'];
246 } else {
247 let outputName = '';
248 let itemValue = '';
249 if (destNode === parentGraphPath + '/' + interfaceName) {
250 let dictItem = this.graphDictionary[parentGraphPath];
251 if (dictItem) {
252 let found = false;
253 for (let item of dictItem) {
254 if (item[0] === parentGraphPath + '/' + interfaceName) {
255 found = true;
256 break;
257 }
258 }
259 if (found) {
260 console.log('Warning: Rename duplicate interface:', parentGraphPath + '/' + interfaceName + ':in');
261 interfaceName = interfaceName + ':in';
262 }
263 }
264 }
265
266 let found = false;
267 let dictItem = this.graphDictionary[parentGraphPath];
268 if (dictItem) {
269 for (let item of dictItem) {
270 if (item[0] === parentGraphPath + '/' + interfaceName) {
271 found = true;
272 break;
273 }
274 }
275 }
276
277 if (!found) {
278 this.updateGraphDictionaryPath(parentGraphPath, parentGraphPath + '/' + interfaceName, 'input', port.getType(), itemValue, this.graphDictionary);
279 }
280 result = [this.appendPath(parentGraphPath, interfaceName), outputName, destNode, destPort, 'interfacename'];
281 }
282 connections.push(result);
283 return;
284 }
285
286 if (outputName) {
287 let result;
288 if (!parentGraphPath) {
289 result = [this.appendPath(outputName, ''), '', parentPath, port.getName(), 'nodename'];
290 } else {
291 result = [this.appendPath(parentGraphPath, outputName), '', parentPath, port.getName(), 'output'];
292 }
293 connections.push(result);
294 return;
295 }
296 }
297
305 buildConnections(doc, graphElement, connections) {
306 let root = doc.getDocument();
307
308 for (let elem of graphElement.getChildren()) {
309 if (!elem.hasSourceUri()) {
310 if (elem instanceof mx.Input) {
311 this.buildPortConnection(root, elem.getNamePath(), connections, true);
312 } else if (elem instanceof mx.Output) {
313 this.buildPortConnection(root, elem.getNamePath(), connections, true);
314 } else if (elem instanceof mx.Node) {
315 let nodeInputs = elem.getInputs();
316 for (let nodeInput of nodeInputs) {
317 this.buildPortConnection(root, nodeInput.getNamePath(), connections, false);
318 }
319 } else if (elem instanceof mx.NodeGraph) {
320 let nodedef = elem.getNodeDef();
321 if (nodedef) {
322 connections.push([elem.getNamePath(), '', nodedef.getName(), '', 'nodedef']);
323 }
324 let visited = new Set();
325 let path = elem.getNamePath();
326 if (!visited.has(path)) {
327 visited.add(path);
328 this.buildConnections(root, elem, connections);
329 }
330 }
331 }
332 }
333 }
334
341 let graphDictionary = {};
342 let root = doc.getDocument();
343 let skipped = [];
344
345 for (let elem of doc.getChildren()) {
346 if (elem.hasSourceUri()) {
347 skipped.push(elem.getNamePath());
348 } else {
349 if ((elem instanceof mx.Input) || (elem instanceof mx.Output) || (elem instanceof mx.Node)) {
350 //console.log('Scan element:', elem.getNamePath(), elem.getCategory(), mx.NodeGraph);
351 this.updateGraphDictionaryItem(elem, graphDictionary);
352 } else if (elem instanceof mx.NodeGraph) {
353 //console.log('Scan graph:', elem.getNamePath(), elem.getCategory(), mx.NodeGraph);
354 if (elem.getAttribute('nodedef')) {
355 let nodeDef = elem.getAttribute('nodedef');
356 nodeDef = root.getDescendant(nodeDef);
357 if (nodeDef) {
358 for (let nodeDefInput of nodeDef.getInputs()) {
359 if (elem.getChild("def_" + nodeDefInput.getName())) {
360 continue;
361 }
362 let newInput = elem.addInput("def_" + nodeDefInput.getName(), nodeDefInput.getType());
363 newInput.copyContentFrom(nodeDefInput);
364 }
365 }
366 }
367
368 for (let node of elem.getInputs()) {
369 this.updateGraphDictionaryItem(node, graphDictionary);
370 }
371 for (let node of elem.getOutputs()) {
372 this.updateGraphDictionaryItem(node, graphDictionary);
373 }
374 for (let node of elem.getNodes()) {
375 this.updateGraphDictionaryItem(node, graphDictionary);
376 }
377 for (let node of elem.getTokens()) {
378 this.updateGraphDictionaryItem(node, graphDictionary);
379 }
380 } else if ((elem instanceof mx.NodeDef) || (elem instanceof mx.Token)) {
381 this.updateGraphDictionaryItem(elem, graphDictionary);
382 }
383 }
384 }
385
386 return graphDictionary;
387 }
388
394 this.connections = [];
395 this.graphDictionary = {};
396
397 let graphElement = this.doc;
398 if (this.includeGraphs) {
399 let graph = this.includeGraphs;
400 graphElement = this.doc.getDescendant(graph);
401 if (graphElement) {
402 graphElement.setSourceUri('');
403 console.log('Scan graph:', graphElement.getNamePath());
404 } else {
405 console.log('Graph not found:', graph);
406 }
407 }
408
409 this.graphDictionary = this.buildGraphDictionary(graphElement);
410 this.buildConnections(this.doc, graphElement, this.connections);
411 }
412
418 getJSON(inputFileName) {
419 let data = {
420 doc: 'Graph connections for: ' + inputFileName,
421 //copyright: 'Copyright 2024, NanMu Consulting. kwokcb@gmail.com',
422 graph: this.graphDictionary,
423 connections: this.connections
424 };
425 return JSON.stringify(data, null, 4);
426 }
427
434 exportToJSON(filename, inputFileName) {
435 let data = {
436 doc: 'Graph connections for: ' + inputFileName,
437 //copyright: 'Copyright 2024, NanMu Consulting. kwokcb@gmail.com',
438 graph: this.graphDictionary,
439 connections: this.connections
440 };
441
442 //let fs = require('fs');
443 //fs.writeFileSync(filename, JSON.stringify(data, null, 2));
444
445 let dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(data, null, 2));
446 let downloadAnchorNode = document.createElement('a');
447 downloadAnchorNode.setAttribute("href", dataStr);
448 downloadAnchorNode.setAttribute("download", filename);
449 document.body.appendChild(downloadAnchorNode); // required for firefox
450 downloadAnchorNode.click();
451 downloadAnchorNode.remove();
452 }
453
459 importFromJSON(filename) {
460 let fs = require('fs');
461 let data = JSON.parse(fs.readFileSync(filename, 'utf8'));
462 this.graphDictionary = data.graph;
463 this.connections = data.connections;
464 }
465}
466
472{
479 constructor(graphDictionary, connections) {
480 this.graphDictionary = graphDictionary;
481 this.connections = connections;
482 this.mermaid = [];
483 this.orientation = 'LR';
484 this.emitCategory = false;
485 this.emitType = false;
486 }
487
493 setOrientation(orientation) {
494 this.orientation = orientation;
495 }
496
502 setEmitCategory(emitCategory) {
503 this.emitCategory = emitCategory;
504 }
505
511 setEmitType(emitType) {
512 this.emitType = emitType;
513 }
514
521 {
522 path = path.replace('/default', '/default1');
523 path = path.replace('/', '_');
524 path = path.replace(' ', '_');
525 return path;
526 }
527
538 let mermaid = [];
539 mermaid.push(`graph ${this.orientation}`);
540
541 for (let graphPath in this.graphDictionary) {
542 let isSubgraph = graphPath !== '';
543 if (isSubgraph) {
544 mermaid.push(` subgraph ${graphPath}`);
545 }
546
547 for (let item of this.graphDictionary[graphPath]) {
548 let path = item[0];
549 let label = path.split('/').pop();
550 // Sanitize the path name
551 path = this.sanitizeString(path)
552
553 if (this.emitCategory) {
554 label = item[1];
555 }
556
557 if (this.emitType) {
558 label += `:${item[2]}`;
559 }
560
561 if (item[3]) {
562 label += `:${item[3]}`;
563 }
564
565 if (['input', 'output'].includes(item[1])) {
566 mermaid.push(` ${path}([${label}])`);
567 mermaid.push(` style ${path} fill:#09D, color:#FFF`);
568 } else if (item[1] === 'surfacematerial') {
569 mermaid.push(` ${path}([${label}])`);
570 mermaid.push(` style ${path} fill:#090, color:#FFF`);
571 } else if (item[1] === 'nodedef') {
572 mermaid.push(` ${path}[[${label}]]`);
573 //mermaid.push(` style ${path} fill:#02F, color:#FFF`);
574 } else if (['ifequal', 'ifgreatereq', 'switch'].includes(item[1])) {
575 mermaid.push(` ${path}{${label}}`);
576 mermaid.push(` style ${path} fill:#C72, color:#FFF`);
577 } else if (item[1] === 'token') {
578 mermaid.push(` ${path}{{${label}}}`);
579 mermaid.push(` style ${path} fill:#222, color:#FFF`);
580 } else if (item[1] === 'constant') {
581 mermaid.push(` ${path}([${label}])`);
582 mermaid.push(` style ${path} fill:#888, color:#000`);
583 } else {
584 mermaid.push(` ${path}[${label}]`);
585 }
586 }
587
588 if (isSubgraph) {
589 mermaid.push(' end');
590 }
591 }
592
593 this.mermaid = mermaid;
594
595 for (let connection of this.connections)
596 {
597 // Sanitize path names
598 connection[0] = this.sanitizeString(connection[0])
599 connection[2] = this.sanitizeString(connection[2])
600
601 let source = connection[0];
602 let dest = connection[2];
603 let edge = '';
604
605 if (connection[1].length > 0) {
606 if (connection[3].length > 0) {
607 edge = `${connection[1]}-->${connection[3]}`;
608 } else {
609 edge = connection[1];
610 }
611 } else {
612 edge = connection[3];
613 }
614
615 let connectString = '';
616
617 if (connection[4] === 'value') {
618 let sourceNode = source.split('/').pop();
619 connectString = edge.length > 0
620 ? ` ${sourceNode}["${source}"] --${edge}--> ${dest}`
621 : ` ${sourceNode}["${source}"] --> ${dest}`;
622 } else {
623 connectString = edge.length > 0
624 ? ` ${source} --"${edge}"--> ${dest}`
625 : ` ${source} --> ${dest}`;
626 }
627
628 mermaid.push(connectString);
629 }
630
631 return mermaid;
632 }
633
639 write(filename) {
640 let fs = require('fs');
641 fs.writeFileSync(filename, this.export());
642 }
643
648 getGraph(wrap = true) {
649 let result = wrap
650 ? '```mermaid\n' + this.mermaid.join('\n') + '\n```'
651 : this.mermaid.join('\n');
652
653 result = result.replace('/default', '/default1');
654 return result;
655 }
656
658 return this.getGraph();
659 }
660}
661
675{
676 let graphBuilder = new MxGraphBuilder(doc);
677 //graphBuilder.importFromJSON(filename);
678 graphBuilder.setIncludeGraphs(opts.graphs)
679 console.log('Creating graph from MaterialX document...')
680 graphBuilder.execute()
681 if (opts.saveJSON)
682 {
683 console.log('Exporting graph to JSON (graph.json)...')
684 graphBuilder.exportToJSON('graph.json', opts.inputFileName)
685 }
686 jsonString = graphBuilder.getJSON(opts.inputFileName)
687
688 //console.log('Dictionary\n', graphBuilder.getDictionary())
689 //console.log('COnnetions\n', graphBuilder.getConnections())
690
691 let exporter = new MxMermaidGraphExporter(
692 graphBuilder.getDictionary(),
693 graphBuilder.getConnections()
694 );
695
696 console.log('Creating Mermaid from graph...')
697 exporter.setOrientation(opts.orientation);
698 exporter.setEmitCategory(opts.emitCategory);
699 exporter.setEmitType(opts.emitType);
700 exporter.execute();
701
702 result = exporter.getGraph(false)
703 return [result, jsonString];
704}
705
711{
715 constructor(compoundGraph) {
716 this.compoundGraph = compoundGraph;
717 this.options = this.getDefaultOptions();
718
719 this.DEFINITION_NAME = 'definitionName';
720 this.UI_NAME = 'uiName';
721 this.NODEGROUP = 'nodeGroup';
722 this.VERSION = 'version';
723 this.DEFAULT_VERSION = 'defaultVersion';
724 this.DEFINITION_PREFIX = 'definitionPrefix';
725 this.NODEGRAPH_PREFIX = 'nodegraphPrefix';
726 this.DOCUMENTATION = 'documentation';
727 this.NAMESPACE = 'namespace';
728 }
729
735 let options = {};
736 options[this.DEFINITION_NAME] = '';
737 options[this.UI_NAME] = '';
738 options[this.VERSION] = '1.0';
739 options[this.DEFAULT_VERSION] = true;
740 options[this.NODEGROUP] = 'procedural';
741 options[this.DEFINITION_PREFIX] = 'ND_';
742 options[this.NODEGRAPH_PREFIX] = 'NG_';
743 options[this.DOCUMENTATION] = '';
744 options[this.NAMESPACE] = '';
745 return options;
746 }
747
754 {
755 console.log('------------ sanitize: ', docString)
756 // Sanitize the string so it's valid for XML and HTML
757 // by replacing special characters with their HTML entities
758 //docString = docString.replace(/&/g, '&')
759 docString = docString.replace(/</g, '&lt;')
760 docString = docString.replace(/>/g, '&gt;')
761
762 // Remove any newlines
763 docString = docString.replace(/(\r\n|\n|\r)/gm, " ");
764
765 console.log('------------ sanitize 2: ', docString)
766 return docString;
767 }
768
774 setOptions(new_options)
775 {
776 //console.log('Set options:', new_options)
777 if (new_options) {
778 this.options = {};
779 for (let key in new_options) {
780 this.options[key] = new_options[key];
781 }
782 }
783 }
784
790 {
791 if (!this.compoundGraph) {
792 return null;
793 }
794 //console.log('Options:', this.options)
795 let nodeGraph = this.compoundGraph;
796
797
798 let category = nodeGraph.getName();
799 if (this.options['definitionName']) {
800 category = this.options['definitionName'];
801 }
802
803 let identifier = "";
804
805 let embedNamespace = true;
806 // Due to lack of robust support for namespace metadata, we will add the namespace
807 // as a prefix to the identifiers
808 let namespace = mx.createValidName(this.options[this.NAMESPACE])
809 // Replace : with _ to avoid issues with namespaces
810 namespace = namespace.replace(':', '_')
811 if (embedNamespace && namespace.length > 0)
812 {
813 category = namespace + '_' + category;
814 }
815 // If category starts with a number or '_' add a "c_" prefix
816 if (category.match(/^[\d_]/)) {
817 console.warn('Category starts with a number. Adding prefix "c_" to category name.')
818 category = 'c' + category;
819 }
820 // Replace all '__' with '_'
821 category = category.replace(/__/g, '_')
822
823 identifier = category;
824 if (this.options[this.VERSION])
825 identifier = identifier + '_' + this.options['version'];
826
827 let parameter_signature = '';
828 let outputs = nodeGraph.getOutputs();
829 for (let output of outputs) {
830 let outputType = output.getType();
831 parameter_signature = parameter_signature + '_' + outputType;
832 }
833 identifier = identifier + parameter_signature;
834 identifier = mx.createValidName(identifier)
835 // Replace all '__' with '_'
836 identifier = identifier.replace(/__/g, '_')
837
838 let nodeDefName = this.options[this.DEFINITION_PREFIX] + identifier;
839 let nodegraphName = this.options[this.NODEGRAPH_PREFIX] + identifier;
840 let uiName = this.options[this.UI_NAME];
841 let defaultVersion = this.options[this.DEFAULT_VERSION];
842 let nodeGroup = this.options[this.NODEGROUP];
843 let version = this.options[this.VERSION]
844
845 let definitionDoc = mx.createDocument();
846
847 // Note that the pre 1.39 equivalent was removed.
848 let definition = definitionDoc.addNodeDefFromGraph(nodeGraph, nodeDefName, category, nodegraphName)
849 if (version.length > 0)
850 {
851 definition.setVersionString(version);
852 }
853 if (defaultVersion)
854 definition.setDefaultVersion(defaultVersion);
855 if (nodeGroup.length > 0)
856 {
857 definition.setNodeGroup(nodeGroup);
858 }
859 let functionalGraph = definitionDoc.getNodeGraph(nodegraphName);
860
861 if (uiName.length)
862 {
863 uiName = this.sanitizeXMLString(uiName)
864 definition.setAttribute('uiname', uiName);
865 }
866
867 if (!embedNamespace && namespace.length > 0)
868 {
869 namespace = mx.createValidName(namespace)
870 definition.setNamespace(namespace);
871 functionalGraph.setNamespace(namespace);
872 // WARNING: Need to rename the nodedef reference
873 functionalGraph.setNodeDefString(namespace + ":" + functionalGraph.getNodeDefString())
874 }
875
876 let docString = this.options[this.DOCUMENTATION]
877 if (docString)
878 {
879 docString = this.sanitizeXMLString(docString)
880 definition.setDocString(docString)
881 functionalGraph.setDocString(docString)
882 }
883
884 /*
885 // Cleanup the result
886 let filterAttributes = ['nodegraph', 'nodename', 'channels', 'interfacename', 'xpos', 'ypos']
887
888 // Transfer input interface from the graph to the nodedef
889 for (let input of functionalGraph.getInputs()) {
890 let nodeDefInput = definition.addInput(input.getName(), input.getType())
891 if (nodeDefInput) {
892 nodeDefInput.copyContentFrom(input)
893 for (let filterAttribute of filterAttributes) {
894 nodeDefInput.removeAttribute(filterAttribute);
895 }
896 nodeDefInput.setSourceUri('')
897 input.setInterfaceName(nodeDefInput.getName())
898 }
899 }
900 for (let input of functionalGraph.getInputs()) {
901 functionalGraph.removeInput(input.getName())
902 }
903
904 for (let output of nodeGraph.getOutputs()) {
905 let nodeDefOutput = definition.getOutput(output.getName())
906 if (nodeDefOutput)
907 definition.removeOutput(output.getName())
908 definition.addOutput(output.getName(), output.getType())
909 if (nodeDefOutput)
910 nodeDefOutput.copyContentFrom(output)
911 for (let filterAttribute in filterAttributes)
912 nodeDefOutput.removeAttribute(filterAttribute)
913 nodeDefOutput.setSourceUri('')
914 }
915 for (let graphChild of functionalGraph.getChildren()) {
916 graphChild.removeAttribute('xpos');
917 graphChild.removeAttribute('ypos');
918 }
919 */
920 return definitionDoc;
921 }
922}
923
931function createMaterialXDefinitionFromNodeGraph(doc, nodeGraphName, options=null)
932{
933 let graph = doc.getDescendant(nodeGraphName)
934 console.log('Creating MaterialX definition from NodeGraph...',
935 graph.getName())
936 let creator = new MxDefinitionCreator(graph);
937 if (options)
938 creator.options = options;
939 return creator.execute();
940}
function createMaterialXDefinitionFromNodeGraph(doc, nodeGraphName, options=null)
Utility to create a MaterialX definition from a node graph.
function createMermaidGraphFromDocument(doc, opts)
Create a Mermaid graph from a MaterialX document.
Class which will create a MaterialX definition from a node graph.
setOptions(new_options)
Set the options for definition creation.
execute()
Create a new definition.
sanitizeXMLString(docString)
Sanitize a string to be safe to use with XML / HTML.
constructor(compoundGraph)
Constructor.
getDefaultOptions()
Get the default options for definition creation.
Class which will build node graph connectivity information from a MaterialX document.
buildPortConnection(doc, portPath, connections, portIsNode)
Store a port connection.
updateGraphDictionaryItem(item, graphDictionary)
Update the graph dictionary with a new item.
getJSON(inputFileName)
Get the JSON representation of the graph information.
exportToJSON(filename, inputFileName)
Export the graph information to a JSON file.
execute()
Build the graph information.
getParentGraph(elem)
Get the parent graph of an element.
updateGraphDictionaryPath(key, item, nodetype, type, value, graphDictionary)
Update the graph dictionary with a new item.
getConnections()
Get graph connections.
getDictionary()
Get the graph dictionary.
buildGraphDictionary(doc)
Build the graph dictionary.
constructor(doc)
Constructor.
importFromJSON(filename)
Import the graph information from a JSON file.
setIncludeGraphs(graphs)
Set graphs to include.
printGraphDictionary(graphDictionary)
Print the graph dictionary.
appendPath(p1, p2)
Append two paths together.
buildConnections(doc, graphElement, connections)
Build the connections between graph elements.
getDefaultOutput(node)
Get the default output of a node.
Class which will export a graph to Mermaid format.
write(filename)
Write the graph to a file.
getGraph(wrap=true)
Get the graph wrapped in a code block if desired.
setEmitCategory(emitCategory)
Set the emit the category versus the node name.
execute()
Build the graph.
setOrientation(orientation)
Set the orientation of the graph.
sanitizeString(path)
Sanitize the a node path to be safe to use with Mermaid.
setEmitType(emitType)
Emit the type of each node in the graph.
constructor(graphDictionary, connections)
Constructor.