APS Viewer を利用するアプリが独自の設定項目を持つ場合があります。このような場面では、Viewer 内の設定パネルを拡張して、設定項目のユーザーイ ンターフェースを用意することが出来ます。実装は、GuiViewer3D.getSettingsPanel メソッドを介して SettingsPanel にアクセスすることで可能です。
HTML ベースで作成するパネルと異なり、特性のメソッドを使ってコントロールを配置していくことになります。例えば、addCheckbox メソッドでチェックボックスを、addDropDownMenu メソッドでドロップダウン メニューを、それぞれ追加することが出来ます。
addTab メソッドで新しいタブの追加も可能です。ただし、Viewer 標準の設定と区別するため、作成したタブの表示は 2 列目になってしまいます。下記例は、APS Viewer:境界ボックス でご紹介した境界ボックスの表示内容を設定したパネルの例です。境界ボックスの作図色と塗潰しの有無、塗潰しを有効にした際の透過度を異なるコントロールで実装しています。
新しいタブを追加すると、下部に設定パネル内のすべてのタブにある項目をリセットする [すべて既定の設定に戻す] ボタンが自動的に配置されます。このボタンのクリック動作は、RESTORE_DEFAULT_SETTINGS_EVENT イベントで取得出来るので、適切なコールバックを用意すれば、標準項目の設定値と同じタイミングで追加した項目の設定値をリセットすることが可能です。
次のコードは、上記の内容を実装したエクステンション BBoxExtension.js の例です。
class BBoxExtension extends Autodesk.Viewing.Extension { constructor(viewer, options) { super(viewer, options); this._group = null; this._button = null; this._enabled = false; this._geom = null; this._material = null; this._mesh = null; this._colorControlId = ""; this._fillControlId = ""; this._opacityControlId = ""; } load = () => { let panel = this.viewer.getSettingsPanel(); let tabId = 999; panel.addTab(tabId, "境界ボックス"); panel.addRow(tabId, "", ""); this._colorControlId = panel.addDropDownMenu(tabId, "表示色", ["黒", "白", "赤", "緑", "青", "黄"], null, 0); this._fillControlId = panel.addCheckbox(tabId, "塗潰し", "塗潰し表示するかを指定", false, (e) => { panel.getControl(this._opacityControlId).setDisabled(!panel.getControl(this._fillControlId).checkElement.checked); this.updateBoundingBox(); }); this._opacityControlId = panel.addSlider(tabId, "透過度", 1, 10, 1, (e) => { this.updateBoundingBox(); }); panel.getControl(this._opacityControlId).setValue(5); panel.getControl(this._opacityControlId).setDisabled(!panel.getControl(this._fillControlId).checkElement.checked); panel.getControl(this._colorControlId).addEventListener("change", (e) => { this.updateBoundingBox(); }); this.viewer.addEventListener(Autodesk.Viewing.RESTORE_DEFAULT_SETTINGS_EVENT, this.onResetSettings); return true; } unload = () => { if (this._group) { this._group.removeControl(this._button); if (this._group.getNumberOfControls() === 0) { this.viewer.toolbar.removeControl(this._group); } } let panel = this.viewer.getSettingsPanel(); let tabId = 999; panel.getControl(this._colorControlId).removeEventListener("change", (e) => { this.removeBoundingBox(); }); panel.removeCheckbox(this._fillControlId); panel.removeDropdownMenu(this._colorControlId); panel.removeTab(tabId); this._fillControlId = ""; this._colorControlId = ""; this.viewer.removeEventListener(Autodesk.Viewing.RESTORE_DEFAULT_SETTINGS_EVENT, this.onResetSettings); this.viewer.removeEventListener(Autodesk.Viewing.SELECTION_CHANGED_EVENT, this.onSelectedByPick); this.viewer.removeEventListener(Autodesk.Viewing.ISOLATE_EVENT, this.onSelectedByMBrowser); this.removeBoundingBox(); return true; } onToolbarCreated = () => { this._group = this.viewer.toolbar.getControl('customExtensions'); if (!this._group) { this._group = new Autodesk.Viewing.UI.ControlGroup('customExtensions'); this.viewer.toolbar.addControl(this._group); } this._button = new Autodesk.Viewing.UI.Button('BBoxExtension'); this._button.onClick = (ev) => { this._enabled = !this._enabled; this._button.setState(this._enabled ? 0 : 1); if (this._enabled) { this.viewer.addEventListener(Autodesk.Viewing.SELECTION_CHANGED_EVENT, this.onSelectedByPick); this.viewer.addEventListener(Autodesk.Viewing.ISOLATE_EVENT, this.onSelectedByMBrowser); this.updateBoundingBox(); } else { this.viewer.removeEventListener(Autodesk.Viewing.SELECTION_CHANGED_EVENT, this.onSelectedByPick); this.viewer.removeEventListener(Autodesk.Viewing.ISOLATE_EVENT, this.onSelectedByMBrowser); this.removeBoundingBox(); } }; this._button.setToolTip(this.options.button.tooltip); this._button.container.children[0].classList.add('fas', this.options.button.icon); this._group.addControl(this._button); } onResetSettings = (e) => { let panel = this.viewer.getSettingsPanel(); panel.getControl(this._fillControlId).checkElement.checked = false; panel.getControl(this._opacityControlId).setDisabled(!panel.getControl(this._fillControlId).checkElement.checked); panel.getControl(this._colorControlId).setSelectedIndex(0); this.updateBoundingBox(); } onSelectedByPick = (e) => { let dbIdArray = e.dbIdArray; console.log("--- onSelectedByPick ---"); this.addBoundingBox(dbIdArray); } onSelectedByMBrowser = (e) => { let dbIdArray = e.nodeIdArray; this.viewer.select(dbIdArray); // force to be 'current' this.viewer.clearSelection(); // console.log("--- onSelectedByMBrowser ---"); this.addBoundingBox(dbIdArray); } addBoundingBox = (dbIdArray) => { if (!this._enabled) return; let bbox; if (dbIdArray.length > 0) { for (var i = 0; i < dbIdArray.length; i++) { var node = dbIdArray[i]; bbox = this.viewer.utilities.getBoundingBox(); console.log("****" + JSON.stringify(bbox)); } const min = JSON.parse(JSON.stringify(bbox.min)); const max = JSON.parse(JSON.stringify(bbox.max)); const xw = max.x - min.x; const yw = max.y - min.y; const zh = max.z - min.z; console.log("x=" + xw + ", y=" + yw + ", z=" + zh); if (this.viewer.overlays.hasScene('boundingbox-scene')) { this.removeBoundingBox(); } let _color = 0x000000; let panel = this.viewer.getSettingsPanel(); switch (panel.getControl(this._colorControlId).selectedIndex) { case 0: _color = 0x000000; break; case 1: _color = 0xffffff; break; case 2: _color = 0xff0000; break; case 3: _color = 0x00ff00; break; case 4: _color = 0x0000ff; break; case 5: _color = 0xffff00; break; } this._geom = new THREE.BoxGeometry(xw, yw, zh); this._material = new THREE.MeshBasicMaterial({ color: _color, wireframe: !panel.getControl(this._fillControlId).checkElement.checked, wireframeLinewidth: 1 }); this._material.transparent = true; if (panel.getControl(this._fillControlId).checkElement.checked) { this._material.opacity = panel.getControl(this._opacityControlId).value * 0.1; } console.log("opacity:" + this._material.opacity); this._mesh = new THREE.Mesh(this._geom, this._material); this._mesh.position.set(min.x + xw / 2, min.y + yw / 2, min.z + zh / 2); if (!this.viewer.overlays.hasScene('boundingbox-scene')) { this.viewer.overlays.addScene('boundingbox-scene'); } this.viewer.overlays.addMesh(this._mesh, 'boundingbox-scene'); } } updateBoundingBox = () => { if (!this._enabled) return; let dbIdArray = this.viewer.getSelection(); if (dbIdArray.length > 0) { this.addBoundingBox(dbIdArray); } else { dbIdArray = this.viewer.getIsolatedNodes(this.viewer.model); if (dbIdArray.length > 0) { this.addBoundingBox(dbIdArray); } else { this.removeBoundingBox(); } } } removeBoundingBox = () => { if (this.viewer.overlays.hasScene('boundingbox-scene')) { this.viewer.overlays.removeMesh(this._mesh, 'boundingbox-scene'); this.viewer.overlays.removeScene('boundingbox-scene'); this._material.dispose(); this._geom.dispose(); this._material = null; this._geom = null; this._mesh = null; } } } Autodesk.Viewing.theExtensionManager.registerExtension('BBoxExtension', BBoxExtension);
設定パネルに追加した「境界ボックス」タブでの実際の動作は、次のようになります。
もし、追加したタブの内容だけをリセットしたい場合には、タブに addButton メソッド で作成したボタンを配置して、setOnClick メソッドでクリック イベントのコールバックを実装、同タブの設定値のリセットを実装することが出来ます。
let panel = NOP_VIEWER.getSettingsPanel(); let tabId = 999; panel.addTab(tabId,"App Settings"); panel.addRow(tabId, "", ""); const controlId = panel.addButton(tabId, "My button"); panel.getControl(controlId).setOnClick((e) => { alert("My button was clicked"); });
By Toshiaki Isezaki
コメント
コメントフィードを購読すればディスカッションを追いかけることができます。