简体   繁体   中英

Forge Autodesk load multiple models in Viewer with ReactJS

We are using Forge Autodesk Viewer to load Forge Models. We are using the framework ReactJS for our application and we have the function bellow to load one model at a viewer:

function loadModel(viewer, documentId) {
    function onDocumentLoadSuccess(viewerDocument) {
        // viewerDocument is an instance of Autodesk.Viewing.Document
        const bubbleNode = viewerDocument.getRoot();
        let defaultModel;

        if (props.phaseName) {
            defaultModel = bubbleNode.getMasterView(props.phaseName);
        } else if (props.guid) {
            defaultModel = bubbleNode.findByGuid(props.guid);
        } else if (props.viewableID) {
            const results = bubbleNode.search({viewableID: props.viewableID});
            if (results && results.length) {
                defaultModel = results[0];
            }
        } else if (props.geomIndex) {
            const geoms = bubbleNode.search({type: "geometry"});
            if (geoms.length) {
                if (props.geomIndex < 0 || props.geomIndex >= geoms.length) {
                    console.warn("GeometryIndex Error: Invalid geometry index.");
                }
                const index = Math.min(Math.max(props.geomIndex, 0), geoms.length - 1); // Ensure index is valid.
                defaultModel = geoms[index];
            }
        }

        if (!defaultModel) defaultModel = bubbleNode.getDefaultGeometry(true);
        const skipHiddenFragments = props.skipHiddenFragments || false;
        viewer.loadDocumentNode(viewerDocument, defaultModel, {
            keepCurrentModels: true,
            skipHiddenFragments: skipHiddenFragments,
        });

     
        viewer.prefs.set("ghosting", false);

            viewer.loadExtension("Autodesk.Viewing.MarkupsCore")
            viewer.loadExtension("Autodesk.Viewing.MarkupsGui")
    }

    function onDocumentLoadFailure() {
        console.error("Failed fetching Forge manifest");
    }

    if (documentId) {
        Autodesk.Viewing.Document.load(
            documentId,
            onDocumentLoadSuccess,
            onDocumentLoadFailure
        );
    } else {
        props.eventBus.dispatchEvent({type: "VIEWER_READY", data: {viewer}});
    }
}

We actually want to know how we could load multiple models using ReactJS. Thank you for your response.

There is no difference in making the code support multiple models between w/ and w/o react.js. You can find lots of examples by searching https://stackoverflow.com/search?q=%5Bautodesk-forge%5D+multiple+models

Anyway...

Here is one for loading multiple models, but you must change the props passed to the Viewer component, and event calls outside the Viewer component accordingly.

//process each promise
//refer to http://jsfiddle.net/jfriend00/h3zaw8u8/
const promisesInSequence = (tasks, callback) => {
    const results = [];
    return tasks.reduce((p, item) => {
      return p.then(() => {
        return callback(item).then((data) => {
          results.push(data);
          return results;
        });
      });
    }, Promise.resolve());
};

const AGGREGATE_GEOMETRY_LOADED_EVENT = 'aggregateGeometryLoaded';

/**
 * @component
 * Component for rendering LMV
 * @param {Object} props
 * @param {("AutodeskProduction"|"AutodeskStaging"|"MD20ProdUS"|"MD20ProdEU")} [props.env] Forge API environment
 * @param {Function} props.getToken Returns the Forge API token to access LMV
 * @param {"derivativeV2"|"derivativeV2_EU"|"modelDerivativeV2"|"fluent"|"D3S"|"D3S_EU"} [props.api] Default = "derivativeV2". Please refer to LMV documentation for more information.
 * @param {Object[]} [props.docUrns] Model data to be loaded
 * @param {string} [modelURNs[].urn] Document URN of the model to be loaded
 * @param {Object} [modelURNs[].options] model options used in loading the specfic model
 * @param {string} [modelURNs[].options.phaseName] phaseName of view to load in scene.
 * @param {string} [modelURNs[].options.guid] guid of BubbleNode to load in scene.
 * @param {string} [modelURNs[].options.viewableID] viewableID of BubbleNode to load in scene.
 * @param {number} [modelURNs[].options.geomIndex] Index of geometry to load in scene.
 * @param {Boolean} [modelURNs[].options.skipHiddenFragments] Boolean to specify if hidden fragments should be skipped (Default: false,
 * Hidden fragments are required for heatmaps in rooms, only applicable to SVF2)
 * @param {OnModelLoaded} [props.onModelLoaded] Callback function invoked when the model has loaded
 * @param {OnViewerInitialized} [props.onViewerInitialized] Callback function invoked when LMV has been intialized
 * @param {string[]} [props.extensions] List of extension ids forwarded to viewer config to load.
 * @param {Object.<string, Object>} [props.disabledExtensions] Default extensions to prevent being loaded.
 * @param {Object} [props.viewerOptions] Options object to forward to Autodesk.Viewing.Initializer
 * @memberof Autodesk.DataVisualization.UI
 * @alias Autodesk.DataVisualization.UI.Viewer
 */
export default function Viewer(props) {
    const viewerRef = useRef(null);
    const viewerDomRef = useRef(null);

    function onModelLoaded(event) {
        const viewer = viewerRef.current;

        // const av = Autodesk.Viewing;
        // viewer.removeEventListener(av.GEOMETRY_LOADED_EVENT, onModelLoaded);
        viewer.removeEventListener(AGGREGATE_GEOMETRY_LOADED_EVENT, onModelLoaded);

        if (props.onModelLoaded) {
            props.onModelLoaded(viewer, event);
        }
    }

    /**
     * Initializes LMV.
     *
     * @memberof Autodesk.DataVisualization.UI
     * @alias Autodesk.DataVisualization.UI.Viewer#initializeViewer
     * @private
     */
    function initializeViewer() {
        let viewerOptions = props.viewerOptions;

        var options = Object.assign({}, viewerOptions, {
            env: props.env,
            api: props.api || "derivativeV2", // for models uploaded to EMEA change this option to 'derivativeV2_EU'
            getAccessToken: async function (onTokenReady) {
                let token = await props.getToken();
                var timeInSeconds = 3600; // Use value provided by Forge Authentication (OAuth) API
                onTokenReady(token, timeInSeconds);
            },
        });

        Autodesk.Viewing.Initializer(options, async function () {
            const extensionsToLoad = props.extensions;

            const extensionsWithConfig = [];
            const extensionsWithoutConfig = [];

            for (let key in extensionsToLoad) {
                const config = extensionsToLoad[key];
                if (Object.keys(config).length === 0) {
                    extensionsWithoutConfig.push(key);
                } else {
                    extensionsWithConfig.push(key);
                }
            }

            const viewer = new Autodesk.Viewing.GuiViewer3D(viewerDomRef.current, {
                extensions: extensionsWithoutConfig,
                disabledExtensions: props.disabledExtensions || {},
            });

            extensionsWithConfig.forEach((ext) => {
                viewer.loadExtension(ext, extensionsToLoad[ext]);
            });

            viewerRef.current = viewer;

            const startedCode = viewer.start(undefined, undefined, undefined, undefined, options);
            if (startedCode > 0) {
                console.error("Failed to create a Viewer: WebGL not supported.");
                return;
            }

            // loadModel(viewer, props.docUrn);
            await loadModels(viewer, props.docUrns);

            if (props.onViewerInitialized) {
                props.onViewerInitialized(viewer);
            }
        });
    }

    /**
     * Loads the specified models into the viewer.
     *
     * @param {Object} viewer Initialized LMV object
     * @param {string} documentId Document URN of the model to be loaded
     * @param {Object} options
     * @param {string} [options.phaseName] phaseName of view to load in scene.
     * @param {string} [options.guid] guid of BubbleNode to load in scene.
     * @param {string} [options.viewableID] viewableID of BubbleNode to load in scene.
     * @param {number} [options.geomIndex] Index of geometry to load in scene.
     * @param {Boolean} [options.skipHiddenFragments] Boolean to specify if hidden fragments should be skipped (Default: false,
     * Hidden fragments are required for heatmaps in rooms, only applicable to SVF2)
     * @memberof Autodesk.DataVisualization.UI
     * @alias Autodesk.DataVisualization.UI.Viewer#loadModelAsync
     * @private
     */
    async function loadModelAsync(viewer, documentId, options) {
        return new Promise((resolve, reject) => {
            async function onDocumentLoadSuccess(viewerDocument) {
                // viewerDocument is an instance of Autodesk.Viewing.Document
                const bubbleNode = viewerDocument.getRoot();
                let defaultModel;

                if (options.phaseName) {
                    defaultModel = bubbleNode.getMasterView(options.phaseName);
                } else if (options.guid) {
                    defaultModel = bubbleNode.findByGuid(options.guid);
                } else if (options.viewableID) {
                    const results = bubbleNode.search({ viewableID: options.viewableID });
                    if (results && results.length) {
                        defaultModel = results[0];
                    }
                } else if (options.geomIndex) {
                    const geoms = bubbleNode.search({ type: "geometry" });
                    if (geoms.length) {
                        if (options.geomIndex < 0 || options.geomIndex >= geoms.length) {
                            console.warn("GeometryIndex Error: Invalid geometry index.");
                        }
                        const index = Math.min(Math.max(options.geomIndex, 0), geoms.length - 1); // Ensure index is valid.
                        defaultModel = geoms[index];
                    }
                }

                if (!defaultModel) defaultModel = bubbleNode.getDefaultGeometry(true);
                const skipHiddenFragments = options.skipHiddenFragments || false;
                let model = await viewer.loadDocumentNode(viewerDocument, defaultModel, {
                    keepCurrentModels: true,
                    skipHiddenFragments: skipHiddenFragments,
                });

                // modify the preference settings, since ghosting is causing heavy z-fighting with the room geometry
                // it would be good we turn it off
                if (!viewer.model)
                    viewer.prefs.set("ghosting", false);

                await viewer.waitForLoadDone();
                resolve(model);
            }

            function onDocumentLoadFailure() {
                console.error("Failed fetching Forge manifest");
            }

            if (documentId) {
                Autodesk.Viewing.Document.load(
                    documentId,
                    onDocumentLoadSuccess,
                    onDocumentLoadFailure
                );
            } else {
                props.eventBus.dispatchEvent({ type: "VIEWER_READY", data: { viewer } });
            }
        });
    }


    /**
     * Loads the specified models into the viewer.
     *
     * @param {Object} viewer Initialized LMV object
     * @param {Object[]} modelURNs Model data to be loaded
     * @param {string} [modelURNs[].urn] Document URN of the model to be loaded
     * @param {Object} [modelURNs[].options] model options used in loading the specfic model
     * @param {string} [modelURNs[].options.phaseName] phaseName of view to load in scene.
     * @param {string} [modelURNs[].options.guid] guid of BubbleNode to load in scene.
     * @param {string} [modelURNs[].options.viewableID] viewableID of BubbleNode to load in scene.
     * @param {number} [modelURNs[].options.geomIndex] Index of geometry to load in scene.
     * @param {Boolean} [modelURNs[].options.skipHiddenFragments] Boolean to specify if hidden fragments should be skipped (Default: false,
     * Hidden fragments are required for heatmaps in rooms, only applicable to SVF2)
     * @memberof Autodesk.DataVisualization.UI
     * @alias Autodesk.DataVisualization.UI.Viewer#loadModelAsync
     * @private
     */
    async function loadModelsAsync(viewer, modelURNs) {
        // const av = Autodesk.Viewing;
        // viewer.addEventListener(av.GEOMETRY_LOADED_EVENT, onModelLoaded, { once: true });
        viewer.addEventListener(AGGREGATE_GEOMETRY_LOADED_EVENT, onModelLoaded, { once: true });

        const results = await promisesInSequence(modelURNs, (d) => loadModelAsync(d.urn, d.options));
        viewer.fireEvent({
            type: AGGREGATE_GEOMETRY_LOADED_EVENT,
            models: results
        });
    }

    useEffect(() => {
        initializeViewer();

        return function cleanUp() {
            if (viewerRef.current) {
                viewerRef.current.finish();
            }
        };
    }, []);

    return <div id="forgeViewer" ref={viewerDomRef}></div>;
}

Viewer.displayName = "Viewer";

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM