1 Apr 2019

Publicly share models in customized Viewer

When on any of the Autodesk Storage solutions (A360, Fusion Team, etc) then you have the option to share your models publicly by inserting an iframe in your webpage:

Share model in iframe

The problem is that in this case the Viewer cannot be customized.

One solution would be to create your own Viewer instance and server for the login mechanism (see View your models), log in once using your credentials, and then keep the login alive for everyone by using the refresh_token - see About Refresh Token  

One other way would be to take advantage of the existing public sharing mechanism and the login endpoint it provides and add it to your webpage. In this case you do not even need to provide server side login mechanism, just serve from somewhere your html page with the JavaScript code in it. The only thing you need to modify in the below code is the value of embedURLfromA360, which should be set to the URL that is inside the iframe tag highlighted above in yellow

<html>
<head>
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=no" />
    <meta charset="utf-8">

    <!-- The Viewer CSS -->
    <link rel="stylesheet" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/6.*/style.min.css" type="text/css">

    <!-- Developer CSS -->
    <style>
        body {
            margin: 0;
        }
        
        #MyConytainerDiv {
            width: 100%;
            height:100%;
            position: relative;
        }

        #MyViewerDiv {
            width: 100%;
            height: 100%;
            margin: 0;
            background-color: #F0F8FF;
        }
    </style>
    
    <title>Showing A360 Shared files</title>
</head>

<body>

    <!-- The Viewer will be instantiated here -->
    <div id="MyConytainerDiv">
        <div id="MyViewerDiv"></div>
    </div>
    
    <!-- The Viewer JS -->
    <script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/6.*/viewer3D.js"></script>

    <!-- jQuery -->
    <script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>

    <!-- Developer JS -->
    <script>
    // this is the iframe URL that shows up when sharing a model embed on a page
    var embedURLfromA360 = 'https://autodesk3743.autodesk360.com/shares/public/SHabee1QT1a327cf2b7a174096650e4352bf?mode=embed'; // Stirling Engine

    var viewer;

    function getURN(onURNCallback) {
        $.get({
            url: embedURLfromA360.replace('public', 'metadata').replace('mode=embed', ''),
            dataType: 'json',
            success: function (metadata) {
                if (onURNCallback) {
                    onURNCallback(metadata.success.body.viewing.views.viewableUrn);
                }
            }
        })
    }

    function getForgeToken(onTokenCallback) {
        $.post({
            url: embedURLfromA360.replace('public', 'sign').replace('mode=embed', 'oauth2=true'),
            data: '{}',
            success: function (oauth) {
                if (onTokenCallback)
                    onTokenCallback(oauth.accessToken, oauth.validitySeconds);
            }
        });
    }

    getURN(function (urn) {
        var options = {
            env: 'AutodeskProduction',
            getAccessToken: getForgeToken
        };
        var documentId = 'urn:' + urn;
        Autodesk.Viewing.Initializer(options, function onInitialized() {
            Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
        });
    });

    // used by viewer.addEventListener(Autodesk.Viewing.TOOLBAR_CREATED_EVENT, onToolbarCreated)
    const onToolbarCreated = (e) => {
        const settingsTools = viewer.toolbar.getControl('settingsTools')
        settingsTools.removeControl('toolbar-modelStructureTool') 
        settingsTools.removeControl('toolbar-propertiesTool')            
        settingsTools.removeControl('toolbar-settingsTool')          
        settingsTools.removeControl('toolbar-fullscreenTool')           

        viewer.removeEventListener(
            Autodesk.Viewing.TOOLBAR_CREATED_EVENT,
            onToolbarCreated)  
    } 

    /**
     * Autodesk.Viewing.Document.load() success callback.
     * Proceeds with model initialization.
     */
    function onDocumentLoadSuccess(doc) {

        // A document contains references to 3D and 2D viewables.
        var viewables = Autodesk.Viewing.Document.getSubItemsWithProperties(doc.getRootItem(), {
            'type': 'geometry'
        }, true);
        if (viewables.length === 0) {
            console.error('Document contains no viewables.');
            return;
        }

        // Choose any of the avialble viewables
        var initialViewable = viewables[0];
        var svfUrl = doc.getViewablePath(initialViewable);
        var modelOptions = {
            sharedPropertyDbPath: doc.getPropertyDbPath()
        };

        var viewerDiv = document.getElementById('MyViewerDiv');
        viewer = new Autodesk.Viewing.Private.GuiViewer3D(viewerDiv);
        
        // Our customization of the Viewer: we are removing some of the toolbar buttons
        viewer.addEventListener(Autodesk.Viewing.TOOLBAR_CREATED_EVENT, onToolbarCreated)
        viewer.start(svfUrl, modelOptions, onLoadModelSuccess, onLoadModelError);
    }

    /**
     * Autodesk.Viewing.Document.load() failuire callback.
     */
    function onDocumentLoadFailure(viewerErrorCode) {}

    /**
     * viewer.loadModel() success callback.
     * Invoked after the model's SVF has been initially loaded.
     * It may trigger before any geometry has been downloaded and displayed on-screen.
     */
    function onLoadModelSuccess(model) {}

    /**
     * viewer.loadModel() failure callback.
     * Invoked when there's an error fetching the SVF file.
     */
    function onLoadModelError(viewerErrorCode) {}
    </script>
</body>
</html>

Now I can just serve this html page from anywhere and get this:

Publicly share model

Since in this case we are using our own Viewer instance therefore we can do all the available customizations to it. ?
E.g. in the above case we are removing some of the toolbar buttons that we do not want the user to see, using the solution shown here: When to remove toolbar buttons   

Related Article