自定義 Forge Viewer 右鍵菜單(Context Menu)

前陣子有些 Autodesk Forge 圈的朋友們都在詢問同一個問題『要怎麼在 Viewer 的自帶右鍵菜單上添加自定義項目或是隻顯示自訂義項目』~ 如下將針對『在自帶右鍵菜單上添加自定義項目』和『只顯示自訂義項目的右鍵菜單』進行說明。canvas

1、 在自帶右鍵菜單上添加自定義項目:api

在自帶右鍵菜單上添加自定義項目是很是容易的,Forge Viewer 提供了一個 API 讓使用者能夠很是輕易的在自帶菜單上添加自個的項目,而你須要作的就是像下面這段代碼同樣作一個簡單的 API 調用。下面這個例子會在右鍵菜單上添加兩個新項目,一個是『改變已選構件的顏色成紅色(Override color of selected elements to red)』,另外一個是『回覆顏色變動(Clear overridden corlor)』:async

viewer.registerContextMenuCallback(  'MyChangingColorMenuItems', ( menu, status ) => {
    if( status.hasSelected ) {
        menu.push({
            title: 'Override color of selected elements to red',
            target: () => {
                const selSet = this.viewer.getSelection();
                this.viewer.clearSelection();

                const color = new THREE.Vector4( 255 / 255, 0, 0, 1 );
                for( let i = 0; i < selSet.length; i++ ) {
                    this.viewer.setThemingColor( selSet[i], color );
                }
            }
        });
    } else {
        menu.push({
            title: 'Clear overridden corlor',
            target: () => {
                this.viewer.clearThemingColors();
            }
        });
    }
});

在執行完上面的代碼後就在右鍵菜單上看到這兩個項目:ide

  1. 『改變已選構件的顏色成紅色(Override color of selected elements to red)』項目將會在有構件被選中時在菜單上顯示:
    改變已選構件的顏色成紅色
  2. 『回覆顏色變動(Clear overridden corlor)』項目會在沒有選中任何構件時出現:
    回覆顏色變動

但通常狀況下,咱們會將上面的代碼放到一個自定義括展裏頭,讓咱們能夠靈活的使用:函數

class MyMenuItemExtension extends Autodesk.Viewing.Extension {
  constructor( viewer, options ) {
    super( viewer, options );

    this.onBuildingContextMenuItem = this.onBuildingContextMenuItem.bind( this );
  }

  get menuId() {
    return 'MyColorContextMenu';
  }

  onBuildingContextMenuItem( menu, status ) {
    if( status.hasSelected ) {
      menu.push({
        title: 'Override color of selected elements to red',
        target: () => {
          const selSet = this.viewer.getSelection();
          this.viewer.clearSelection();

          // Change color of selected elements to the red
          const color = new THREE.Vector4( 255 / 255, 0, 0, 1 );
          for( let i = 0; i < selSet.length; i++ ) {
            this.viewer.setThemingColor( selSet[i], color );
          }
        }
      });

    } else {
      menu.push({
        title: 'Clear overridden corlor',
        target: () => {
          this.viewer.clearThemingColors();
        }
      });
    }
  }

  load() {
    // Add my owned menu items
    this.viewer.registerContextMenuCallback(
      this.menuId,
      this.onBuildingContextMenuItem
    );

    return true;
  }

  unload() {
    // Remove all menu items added from this extension
    this.viewer.unregisterContextMenuCallback( this.menuId );

    return true;
  }
}

Autodesk.Viewing.theExtensionManager.registerExtension( 'DemoMenuExtension', MyMenuItemExtension );


2、 只顯示自訂義項目的右鍵菜單:post

若是上頭的代碼與你的需求不符合,你能夠考慮編寫一自訂義的右鍵菜單,同樣的他也不會太困難。如今舉個例子來講明,像如今若是我想讓自帶右鍵菜單上除了自帶項目外,還會在點擊到不一樣構件時顯示不一樣的項目;我須要作的就是經過繼承 Autodesk.Viewing.Extensions.ViewerObjectContextMenu 和加入 hitTest 相關的邏輯到自定義右鍵菜單的 buildMenu 函數,就像下面這樣:ui

class MyContextMenu extends Autodesk.Viewing.Extensions.ViewerObjectContextMenu {
  constructor( viewer ) {
    super( viewer );
  }

  isWall( dbId ) {
    //Logics for determining if selected element is wall or not.
    return new Promise( ( resolve, reject ) => {
        $.get(
            '/api/walls/' + dbId,
            ( response ) => {
                if( response && response.id != 0 ) {
                    return resolve( true );
                }
                return resolve( false );
            }
        )
        .error( ( error ) => reject( error ) );
    });
  }

  async buildMenu( event, status ) {
    // Get defulat menu items from the super class
    const menu = super.buildMenu( event, status );

    // Do hitTest to get dbIds
    const viewport = this.viewer.container.getBoundingClientRect();
    const canvasX = event.clientX - viewport.left;
    const canvasY = event.clientY - viewport.top;

    const result = this.viewer.impl.hitTest( canvasX, canvasY, false );

    if( !result || !result.dbId ) return menu;

    let isWall = false;
    try {
        isWall = await this.isWall( result.dbId );
    } catch ( error ) {
        isWall = false;
    }

    if( status.hasSelected && isWall ) {
      menu.push({
          title: 'Show current surface temperature map',
          target: () => {
              $.post(
                    '/api/walls/temperature',
                    ( response ) => {
                        ViewerUtil.showWallTemperatureMap( response.values );
                    }
              );
          }
      });
    }

    return menu;
   }

   /**
    * @override
    */
   async show( event ) {
    const numSelected = this.viewer.getSelectionCount();
    const visibility = this.viewer.getSelectionVisibility();
    const status = {
      numSelected: numSelected,
      hasSelected: ( numSelected > 0 ),
      hasVisible: visibility.hasVisible,
      hasHidden: visibility.hasHidden
    };
    const menu = await this.buildMenu( event, status );

    this.viewer.runContextMenuCallbacks( menu, status );

    if( menu && menu.length > 0 ) {
      this.contextMenu.show( event, menu );
    }
   }
}

class MyContextMenuExtension extends Autodesk.Viewing.Extension {
    constructor( viewer, options ) {
        super( viewer, options );
    }

    load() {
        // Use my owned context menu.
        this.viewer.setContextMenu( new MyContextMenu( this.viewer ) );
        return true;
    }

    unload() {
        // Restore default context menu
        this.viewer.setContextMenu( new Autodesk.Viewing.Extensions.ViewerObjectContextMenu( this.viewer ) );
        return true;
    }
}

Autodesk.Viewing.theExtensionManager.registerExtension( 'DemoWallMenuExtension', MyContextMenuExtension );

這樣子就會在點擊到牆構件顯示這個項目『Show current surface temperature map』:
圖片描述this

相反的,若是你不想顯示菜單上自帶的項目,你能夠改爲繼承 Autodesk.Viewing.UI.ObjectContextMenu。但你點擊到牆構件的時候就只會顯示『Show current surface temperature map』這個項目,就像下面這個樣子:
圖片描述spa

但願上面的說明對各位使用 Autodesk Forge 的朋友們有些幫助~code

相關文章
相關標籤/搜索