Панель инструментов Forge Basic Skeleton Example не заполняется

Я уже сталкивался с эта почта, у которого очень похожая проблема.

Моя проблема в том, что после того, как я убедился, что все мои ссылки точны и написаны правильно, я все еще не могу понять, почему кнопка не появляется. Я также добавил собственный img/icon.png размером 24x24 пикселей.

Ниже мои index.html, ForgeViewr.js, MyAwesomeExtension.js и main.css.

Спасибо вам за помощь!

Вот снимок экрана с текущими панелями инструментов, которые появляются, когда я создаю проект как есть.

показатель

<head>
    <title>Autodesk Forge Tutorial</title>
    <meta charset = "utf-8" />
    <!-- Common packages: jQuery, Bootstrap, jsTree -->
    <script src = "//cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src = "//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script src = "//cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>
    <link rel = "stylesheet" href = "//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
    <link rel = "stylesheet" href = "//cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" />
    <!-- Autodesk Forge Viewer files -->
    <link rel = "stylesheet" href = "https://developer.api.autodesk.com/modelderivative/v2/viewers/style.min.css?v=v6.0" type = "text/css">
    <script src = "https://developer.api.autodesk.com/modelderivative/v2/viewers/viewer3D.min.js?v=v6.0"></script>
    <!-- this project files -->
    <link href = "css/main.css" rel = "stylesheet" />
    <script src = "js/MyAwesomeExtension.js"></script>
    <script src = "js/ForgeTree.js"></script>
    <script src = "js/ForgeViewer.js"></script>
</head>

<body>
  <!-- Fixed navbar by Bootstrap: https://getbootstrap.com/examples/navbar-fixed-top/ -->
  <nav class = "navbar navbar-default navbar-fixed-top">
    <div class = "container-fluid">
      <ul class = "nav navbar-nav left">
        <li>
          <a href = "http://developer.autodesk.com" target = "_blank">
            <img alt = "Autodesk Forge" src = "//developer.static.autodesk.com/images/logo_forge-2-line.png" height = "20">
          </a>
        </li>
      </ul>
    </div>
  </nav>
  <!-- End of navbar -->
  <div class = "container-fluid fill">
    <div class = "row fill">
      <div class = "col-sm-3 fill">
        <div class = "panel panel-default fill">
          <div class = "panel-heading" data-toggle = "tooltip">
            Buckets &amp; Objects
            <span id = "refreshBuckets" class = "glyphicon glyphicon-refresh" style = "cursor: pointer"></span>
            <button class = "btn btn-xs btn-info" style = "float: right" id = "showFormCreateBucket" data-toggle = "modal" data-target = "#createBucketModal">
              <span class = "glyphicon glyphicon-folder-close"></span> New bucket
            </button>
          </div>
          <div id = "appBuckets">
            tree here
          </div>
        </div>
      </div>
      <div class = "col-sm-9 fill">
        <div id = "forgeViewer"></div>
      </div>
    </div>
  </div>
  <form id = "uploadFile" method='post' enctype = "multipart/form-data">
    <input id = "hiddenUploadField" type = "file" name = "theFile" style = "visibility:hidden" />
  </form>
  <!-- Modal Create Bucket -->
  <div class = "modal fade" id = "createBucketModal" tabindex = "-1" role = "dialog" aria-labelledby = "myModalLabel">
    <div class = "modal-dialog" role = "document">
      <div class = "modal-content">
        <div class = "modal-header">
          <button type = "button" class = "close" data-dismiss = "modal" aria-label = "Cancel">
            <span aria-hidden = "true">&times;</span>
          </button>
          <h4 class = "modal-title" id = "myModalLabel">Create new bucket</h4>
        </div>
        <div class = "modal-body">
          <input type = "text" id = "newBucketKey" class = "form-control"> For demonstration purpouses, objects (files) 
          are NOT automatically translated. After you upload, right click on
          the object and select "Translate".
        </div>
        <div class = "modal-footer">
          <button type = "button" class = "btn btn-default" data-dismiss = "modal">Cancel</button>
          <button type = "button" class = "btn btn-primary" id = "createNewBucket">Go ahead, create the bucket</button>
        </div>
      </div>
    </div>
  </div>
</body>

</html>

ForgeViewer

var viewerApp;

function launchViewer(urn) {
  var options = {
    env: 'AutodeskProduction',
    getAccessToken: getForgeToken
  };
  var documentId = 'urn:' + urn;
  Autodesk.Viewing.Initializer(options, function onInitialized() {
    viewerApp = new Autodesk.Viewing.ViewingApplication('forgeViewer');
    viewerApp.registerViewer(viewerApp.k3D, Autodesk.Viewing.Private.GuiViewer3D, { extensions: ['MyAwesomeExtension'] });
    viewerApp.loadDocument(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
  });
}

function onDocumentLoadSuccess(doc) {
  // We could still make use of Document.getSubItemsWithProperties()
  // However, when using a ViewingApplication, we have access to the **bubble** attribute,
  // which references the root node of a graph that wraps each object from the Manifest JSON.
  var viewables = viewerApp.bubble.search({ 'type': 'geometry' });
  if (viewables.length === 0) {
    console.error('Document contains no viewables.');
    return;
  }

  // Choose any of the avialble viewables
  viewerApp.selectItem(viewables[0].data, onItemLoadSuccess, onItemLoadFail);
}

function onDocumentLoadFailure(viewerErrorCode) {
  console.error('onDocumentLoadFailure() - errorCode:' + viewerErrorCode);
}

function onItemLoadSuccess(viewer, item) {
  // item loaded, any custom action?
}

function onItemLoadFail(errorCode) {
  console.error('onItemLoadFail() - errorCode:' + errorCode);
}

function getForgeToken(callback) {
  jQuery.ajax({
    url: '/api/forge/oauth/token',
    success: function (res) {
      callback(res.access_token, res.expires_in)
    }
  });
}

MyAwesomeExtension

myawesomeextension

// *******************************************
// My Awesome Extension
// *******************************************
function MyAwesomeExtension(viewer, options) {
    Autodesk.Viewing.Extension.call(this, viewer, options);
}

MyAwesomeExtension.prototype = Object.create(Autodesk.Viewing.Extension.prototype);
MyAwesomeExtension.prototype.constructor = MyAwesomeExtension;

MyAwesomeExtension.prototype.load = function () {
    if (this.viewer.toolbar) {
        // Toolbar is already available, create the UI
        this.createUI();
    } else {
        // Toolbar hasn't been created yet, wait until we get notification of its creation
        this.onToolbarCreatedBinded = this.onToolbarCreated.bind(this);
        this.viewer.addEventListener(Autodesk.Viewing.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded);
    }
    return true;
};

MyAwesomeExtension.prototype.onToolbarCreated = function () {
    this.viewer.removeEventListener(Autodesk.Viewing.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded);
    this.onToolbarCreatedBinded = null;
    this.createUI();
};

MyAwesomeExtension.prototype.createUI = function () {
    var _this = this;

    // prepare to execute the button action
    var myAwesomeToolbarButton = new Autodesk.Viewing.UI.Button('runMyAwesomeCode');
    myAwesomeToolbarButton.onClick = function (e) {

        // **********************
        //
        //
        // Execute an action here
        //
        //
        // **********************

        alert('I am an extension');

    };
    // myAwesomeToolbarButton CSS class should be defined on your .css file
    // you may include icons, below is a sample class:

    myAwesomeToolbarButton.addClass('myAwesomeToolbarButton');
    myAwesomeToolbarButton.setToolTip("My Awesome extension's tooltip");

    // SubToolbar
    this.subToolbar = (this.viewer.toolbar.getControl("MyAppToolbar") ?
        this.viewer.toolbar.getControl("MyAppToolbar") :
        new Autodesk.Viewing.UI.ControlGroup('MyAppToolbar'));
    this.subToolbar.addControl(myAwesomeToolbarButton);

    this.viewer.toolbar.addControl(this.subToolbar);
};

MyAwesomeExtension.prototype.unload = function () {
    this.viewer.toolbar.removeControl(this.subToolbar);
    return true;
};

Autodesk.Viewing.theExtensionManager.registerExtension('MyAwesomeExtension', MyAwesomeExtension);

главный

html, body{
  min-height: 100%;
  height: 100%;
}

.fill{
  height: calc(100vh - 100px);
}

body {
  padding-top: 60px; /* space for the top nav bar */
  margin-right: 30px;
}

#appBuckets {
  overflow: auto;
  width: 100%;
  height: calc(100vh - 150px);
}

#forgeViewer {
  width: 100%;
}

.myAwesomeToolbarButton {
    background-image: url(img/icon.png);
    background-size: 24px;
    background-repeat: no-repeat;
    background-position: center;
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
280
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Попробуйте зарегистрировать расширение непосредственно в Viewer3D, а не в ViewerApplication. Я не вижу ничего другого с вашим расширением или Html / CSS, и приведенное ниже работает хорошо:

  var viewer = new Autodesk.Viewing.Private.GuiViewer3D(myViewerDiv,{ extensions: ['MyAwesomeExtension'] });

Полный код: https://jsfiddle.net/dukedhx/x80tmwcu/1/

Другие вопросы по теме