此篇文章原做是 Autodesk ADN Philippe Leefsma,如下以我简称。javascript
这有一个简易的博客用来讲明一个我刚加入 https://forge-rcdb.autodesk.io 的一个新功能,他主要是提供一个使用介面让使用者能够在一个文档(Forge Document)里不一样的视图(Forge Viewable)间快速的切换。A360 viewer有提供相似的功能,但这并不包含在 Forge Viewer 里头。css
在 Forge Document 里。条列 Viewable 清单或是切换视图是很是容易的,你主要是要创建一个使用者介面让使用者去选取他们想观看的内容。若是您不知道要怎么让 Forge Model Derivative 服务帮您转换多个视图,请先看看这篇文章:为何Revit模型有多个视图,丢到 Forge 转换后确只剩一个? (如何设定多个视图)html
接著让咱们来看看该怎么实做这个功能(我全部的代码都有用到 ES六、async/await,UI的部份使用了 React):java
1、从已转换好的 URN 载入 Document:react
///////////////////////////////////////////////////////// // Load a document from URN // ///////////////////////////////////////////////////////// static loadDocument (urn) { return new Promise((resolve, reject) => { const paramUrn = !urn.startsWith('urn:') ? 'urn:' + urn : urn Autodesk.Viewing.Document.load(paramUrn, (doc) => { resolve (doc) }, (error) => { reject (error) }) }) }
2、从已载入的 Document 物件获取全部 Viewable 清单:segmentfault
///////////////////////////////////////////////////////// // Return viewables // ///////////////////////////////////////////////////////// static getViewableItems (doc, roles = ['3d', '2d']) { const rootItem = doc.getRootItem() let items = [] const roleArray = roles ? (Array.isArray(roles) ? roles : [roles]) : [] roleArray.forEach((role) => { items = [ ...items, ...Autodesk.Viewing.Document.getSubItemsWithProperties( rootItem, { type: 'geometry', role }, true) ] }) return items }
3、载入已选中的 Viewable:
首先,我门要把已载入的模型先卸载,下面的样例是假设咱们已经载入了一个模型,如今使用者选择了新的 Viewable
要 Forge Viewer 载入。我使用了 viewer.tearDown()
来确保当前载入模型占用的内存能够都被释出。这个样例也支持从 3D 模型切换到 2D 模型,或者是反过来;您能够忽略我代码里使用到的 React 相关的代码。api
///////////////////////////////////////////////////////// // Load the selected viewable // ///////////////////////////////////////////////////////// onItemSelected (item) { const {activeItem} = this.react.getState() if (item.guid !== activeItem.guid) { this.viewer.tearDown() this.viewer.start() const path = this.viewerDocument.getViewablePath(item) this.viewer.loadModel(path) this.react.setState({ activeItem: item }) } }
完整的代码以下所示,对这功能有兴趣的朋友们能够经过这个网址 https://forge-rcdb.autodesk.i...,并载入 Viewable Selector
来体验。app
///////////////////////////////////////////////////////// // Viewing.Extension.ViewableSelector // by Philippe Leefsma, November 2017 // ///////////////////////////////////////////////////////// import MultiModelExtensionBase from 'Viewer.MultiModelExtensionBase' import './Viewing.Extension.ViewableSelector.scss' import WidgetContainer from 'WidgetContainer' import ReactTooltip from 'react-tooltip' import ServiceManager from 'SvcManager' import Toolkit from 'Viewer.Toolkit' import ReactDOM from 'react-dom' import Image from 'Image' import Label from 'Label' import React from 'react' class ViewableSelectorExtension extends MultiModelExtensionBase { ///////////////////////////////////////////////////////// // Class constructor // ///////////////////////////////////////////////////////// constructor (viewer, options) { super (viewer, options) this.react = options.react } ///////////////////////////////////////////////////////// // // ///////////////////////////////////////////////////////// get className() { return 'viewable-selector' } ///////////////////////////////////////////////////////// // Extension Id // ///////////////////////////////////////////////////////// static get ExtensionId() { return 'Viewing.Extension.ViewableSelector' } ///////////////////////////////////////////////////////// // Load callback // ///////////////////////////////////////////////////////// load () { this.react.setState({ activeItem: null, items: [] }).then (async() => { const urn = this.options.model.urn this.viewerDocument = await this.options.loadDocument(urn) const items = await Toolkit.getViewableItems( this.viewerDocument) if (items.length > 1) { this.createButton() await this.react.setState({ activeItem: items[0], items: [items[0], items[1], items[2]] }) if (this.options.showPanel) { this.showPanel (true) } } }) console.log('Viewing.Extension.ViewableSelector loaded') return true } ///////////////////////////////////////////////////////// // Unload callback // ///////////////////////////////////////////////////////// unload () { this.react.popViewerPanel(this) console.log('Viewing.Extension.ViewableSelector unloaded') return true } ///////////////////////////////////////////////////////// // Load the selected viewable // ///////////////////////////////////////////////////////// onItemSelected (item) { const {activeItem} = this.react.getState() if (item.guid !== activeItem.guid) { this.viewer.tearDown() this.viewer.start() const path = this.viewerDocument.getViewablePath(item) this.viewer.loadModel(path) this.react.setState({ activeItem: item }) } } ///////////////////////////////////////////////////////// // Create a button to display the panel // ///////////////////////////////////////////////////////// createButton () { this.button = document.createElement('button') this.button.title = 'This model has multiple views ...' this.button.className = 'viewable-selector btn' this.button.innerHTML = 'Views' this.button.onclick = () => { this.showPanel(true) } const span = document.createElement('span') span.className = 'fa fa-list-ul' this.button.appendChild(span) this.viewer.container.appendChild(this.button) } ///////////////////////////////////////////////////////// // Show/Hide panel // ///////////////////////////////////////////////////////// showPanel (show) { if (show) { const {items} = this.react.getState() this.button.classList.add('active') const container = this.viewer.container const height = Math.min( container.offsetHeight - 110, (items.length + 1) * 78 + 55) this.react.pushViewerPanel(this, { maxHeight: height, draggable: false, maxWidth: 500, minWidth: 310, width: 310, top: 30, height }) } else { this.react.popViewerPanel(this.id).then(() => { this.button.classList.remove('active') }) } } ///////////////////////////////////////////////////////// // Render React panel content // ///////////////////////////////////////////////////////// renderContent () { const {activeItem, items} = this.react.getState() const urn = this.options.model.urn const apiUrl = this.options.apiUrl const domItems = items.map((item) => { const active = (item.guid === activeItem.guid) ? ' active' :'' const query = `size=400&guid=${item.guid}` const src = `${apiUrl}/thumbnails/${urn}?${query}` return ( <div key={item.guid} className={"item" + active} onClick={() => this.onItemSelected(item)}> <div className="image-container" data-for={`thumbnail-${item.guid}`} data-tip> <Image src={src}/> </div> <ReactTooltip id={`thumbnail-${item.guid}`} className="tooltip-thumbnail" delayShow={700} effect="solid" place="right"> <div> <img src={src} height="200"/> </div> </ReactTooltip> <Label text={item.name}/> </div> ) }) return ( <div className="items"> {domItems} <div style={{height: '80px'}}/> </div> ) } ///////////////////////////////////////////////////////// // Render title // ///////////////////////////////////////////////////////// renderTitle () { return ( <div className="title"> <label> Select Viewable </label> <div className="viewable-selector-controls"> <button onClick={() => this.showPanel(false)} title="Toggle panel"> <span className="fa fa-times"/> </button> </div> </div> ) } ///////////////////////////////////////////////////////// // Render main // ///////////////////////////////////////////////////////// render (opts) { return ( <WidgetContainer renderTitle={() => this.renderTitle(opts.docked)} showTitle={opts.showTitle} className={this.className}> {this.renderContent()} </WidgetContainer> ) } } Autodesk.Viewing.theExtensionManager.registerExtension( ViewableSelectorExtension.ExtensionId, ViewableSelectorExtension)