When someone clicks on points on the data, I want call custom function to show some image or information.
I am using Vega-lite in ObservableHQ notebooks and couldn't find answer?
const chart = (type)=>{
return vl
.markCircle({size: 15, opacity: 0.9})
.autosize('fit')
.data(getData(type))
.encode(
vl.x().fieldQ('slice').title('Slice'),
vl.y().fieldQ('dice').title(type).scale({domain: [0, 1.0]}),
vl.color().field('algorithm').title('Algorithm'),
vl.tooltip(['slice', 'algorithm', 'dice'])
)
}
const types = ['DSC','SDSC_2mm']
const charts = []
types.map(type => {
charts.push(chart(type))
})
return vl.vconcat(vl.hconcat(charts)).render()
}
This is the code I have in notebook.
If you just care about click, you can do something like the first cell in this notebook: https://observablehq.com/#visnup/vega-lite-data-out
Specifically:
clicked = Generators.observe((notify) => {
const clicked = (event, {datum}) => notify(datum);
clickable.addEventListener("click", clicked);
return () => clickable.removeEventListener("click", clicked);
})
where clickable is the name of my chart from the other cell.
A better-than-clickable example would be to do the same thing for Vega-Lite selections. I've added that to the notebook too.
selected = Generators.observe((notify) => {
const signal = Object.keys(selectable.getState({ signals: (name) => name.match(/^sel\d+$/) }).signals)[0];
const selected = (selection, predicates) => {
const within = penguins.filter(d => {
for (const [key, [min, max]] of Object.entries(predicates))
if (isNaN(+d[key]) || d[key] < min || d[key] > max)
return false;
return true;
})
notify(within);
}
selectable.addSignalListener(signal, selected);
return () => selectable.removeEventListener(signal, selected);
})
Related
I have multiple charts in my home page and I have a search box to filter them by chart name.
when I filter particular chart I can delete that chart while it's begin filtered and it disappear from UI but some reason the chart that I just deleted still appear in the home page with the rest of the other charts when I unfiltered/removed all the text in the search box.
It got deleted in the backend but the deleted chart is still appearing in the front end. Also for some reason I can still search it again the one that I just deleted but this time I can not delete it again since it throw 404.
It only disappear completely when I refresh the browser. Any suggestion on how I can make the chart to disappear even after I unfiltered in the search box.
HTML
//Imported this component to display a list of chart
<ng-container *ngFor="let chart of charts">
<mc-chart-list [chart]="chart" [wsType]="workspace.type" (removeFromList)="onRemoveFromList($event)"></mc-chart-list>
</ng-container>
//I use this searchbar to filter by the name of the chart
<input class="input" matInput name="query" [formControl]="query" placeholder="Filter Workspace">
TS
#Input() chart: Chart;
workspace: Workspace;
private death$: Subject<void> = new Subject();
query: FormControl = new FormControl();
charts: Chart[] = [];
searchText: string;
ngOnInit(): void {
this.activatedRoute.paramMap.pipe(takeUntil(this.death$)).subscribe((paramMap) => {
const guid = paramMap.get('guid');
if (guid) {
this.workspaceService.getWorkspace(guid, this.isPublished).subscribe(ws => {
this.workspace = ws;
}, () => this.loading = false);
}
})
//For search bar
this.query.valueChanges
.pipe(takeUntil(this.death$))
.subscribe((value: string) => {
this.search(value);
});
}
search(searchText: string){
// reset
searchText = searchText.toLowerCase();
if (!searchText || searchText.length == 0) {
this.charts = this.workspace.charts;
}
// search
else {
this.charts = this.charts.filter(chart => chart.name.toLowerCase().indexOf(searchText) >= 0);
}
}
onRemoveFromList(id: number) {
const index = this.charts.findIndex(e => e.id === id);
if (index >= 0) {
this.charts.splice(index, 1);
}
I can do this.ngOnIt() inside the search funtion but I don't think that will be best way to do it so I'll be really appreciated if someone can help me fix this.
your workspace.charts have the all the charts.you are assigning value for charts from workspace.charts.In your onRemoveFromList function you only remove it from chart.but workspace.charts still have that removed value.then whenever you reset the search the removed values going in to the charts that is why you see those removed charts.
Solution: in your onRemoveFromList remove the chart from workspace.charts too.
onRemoveFromList(id: number) {
const index = this.charts.findIndex(e => e.id === id);
if (index >= 0) {
this.charts.splice(index, 1);
this.workspace.charts = this.workspace.charts.filter(e => e.id !== id);
}
i am working with Forge viewer, in Revit file we are creating some elements as groups. when that Revit file uploading in forge viewer we cannot find any grouping data which given in Revit, we can only saw total element wise groups. is there any way to get the Revit groups into forge viewer?..... please help us to solve this issue.
Except for those two methods advised by Jeremy. There is another way to achieve it by querying viewer property DB.
Currently, Revit groups are not a part of the model structure panel (Instance tree) and don't have a concrete mesh linked to them, so we cannot play with them in the viewer directly, but fortunately they can be found inside the viewer property DB.
Here is a small demo for proving this possibility, please have a try:
//
// Copyright (c) Autodesk, Inc. All rights reserved
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Forge Autodesk.ADN.RevitGroupPanel
// by Eason Kang - Autodesk Developer Network (ADN)
//
'use strict';
(function() {
function userFunction( pdb ) {
let _nameAttrId = pdb.getAttrName();
let _internalGroupRefAttrId = -1;
// Iterate over all attributes and find the index to the one we are interested in
pdb.enumAttributes(function(i, attrDef, attrRaw){
let category = attrDef.category;
let name = attrDef.name;
if( name === 'Group' && category === '__internalref__' ) {
_internalGroupRefAttrId = i;
return true; // to stop iterating over the remaining attributes.
}
});
//console.log( _internalGroupRefAttrId );
// Early return is the model doesn't contain data for "Group".
if( _internalGroupRefAttrId === -1 )
return null;
let _internalMemberRefAttrId = -1;
// Iterate over all attributes and find the index to the one we are interested in
pdb.enumAttributes(function(i, attrDef, attrRaw){
let category = attrDef.category;
let name = attrDef.name;
if( name === 'Member' && category === '__internalref__' ) {
_internalMemberRefAttrId = i;
return true; // to stop iterating over the remaining attributes.
}
});
//console.log( _internalMemberRefAttrId );
// Early return is the model doesn't contain data for "Member".
if( _internalMemberRefAttrId === -1 )
return null;
let _categoryAttrId = -1;
// Iterate over all attributes and find the index to the one we are interested in
pdb.enumAttributes(function(i, attrDef, attrRaw){
let category = attrDef.category;
let name = attrDef.name;
if( name === 'Category' && category === '__category__' ) {
_categoryAttrId = i;
return true; // to stop iterating over the remaining attributes.
}
});
//console.log( _categoryAttrId );
// Early return is the model doesn't contain data for "Member".
if( _categoryAttrId === -1 )
return null;
const groups = [];
// Now iterate over all parts to find all groups
pdb.enumObjects(function( dbId ) {
let isGroup = false;
// For each part, iterate over their properties.
pdb.enumObjectProperties( dbId, function( attrId, valId ) {
// Only process 'Caegory' property.
// The word "Property" and "Attribute" are used interchangeably.
if( attrId === _categoryAttrId ) {
const value = pdb.getAttrValue( attrId, valId );
if( value === 'Revit Group' ) {
isGroup = true;
// Stop iterating over additional properties when "Caegory: Revit Group" is found.
return true;
}
}
});
if( !isGroup ) return;
const children = [];
let groupName = '';
// For each part, iterate over their properties.
pdb.enumObjectProperties( dbId, function( attrId, valId ) {
// Only process 'Member' property.
// The word "Property" and "Attribute" are used interchangeably.
if( attrId === _internalMemberRefAttrId ) {
const value = pdb.getAttrValue( attrId, valId );
children.push( value );
}
if( attrId === _nameAttrId ) {
const value = pdb.getAttrValue( attrId, valId );
groupName = value;
}
});
groups.push({
dbId,
name: groupName,
children
});
});
return groups;
}
class AdnRevitGroupPanel extends Autodesk.Viewing.UI.DockingPanel {
constructor( viewer, title, options ) {
options = options || {};
// Height adjustment for scroll container, offset to height of the title bar and footer by default.
if( !options.heightAdjustment )
options.heightAdjustment = 70;
if( !options.marginTop )
options.marginTop = 0;
super( viewer.container, viewer.container.id + 'AdnRevitGroupPanel', title, options );
this.container.classList.add( 'adn-docking-panel' );
this.container.classList.add( 'adn-rvt-group-panel' );
this.createScrollContainer( options );
this.viewer = viewer;
this.options = options;
this.uiCreated = false;
this.addVisibilityListener(( show ) => {
if( !show ) return;
if( !this.uiCreated )
this.createUI();
});
}
async getGroupData() {
try {
return await this.viewer.model.getPropertyDb().executeUserFunction( userFunction );
} catch( ex ) {
console.error( ex );
return null;
}
}
async requestContent() {
const data = await this.getGroupData();
if( !data ) return;
for( let i=0; i<data.length; i++ ) {
const div = document.createElement( 'div' );
div.innerText = `${ data[i].name }(${ data[i].children.length })`;
div.title = `DbId: ${ data[i].dbId }`;
div.addEventListener(
'click',
( event ) => {
event.stopPropagation();
event.preventDefault();
this.viewer.clearSelection();
this.viewer.select( data[i].children );
this.viewer.fitToView( data[i].children );
});
this.scrollContainer.appendChild( div );
}
this.resizeToContent();
}
async createUI() {
this.uiCreated = true;
if( this.viewer.model.isLoadDone() ) {
this.requestContent();
} else {
this.viewer.addEventListener(
Autodesk.Viewing.GEOMETRY_LOADED_EVENT,
() => this.requestContent(),
{ once: true }
);
}
}
}
class AdnRevitGroupPanelExtension extends Autodesk.Viewing.Extension {
constructor( viewer, options ) {
super( viewer, options );
this.panel = null;
this.createUI = this.createUI.bind( this );
this.onToolbarCreated = this.onToolbarCreated.bind( this );
}
onToolbarCreated() {
this.viewer.removeEventListener(
Autodesk.Viewing.TOOLBAR_CREATED_EVENT,
this.onToolbarCreated
);
this.createUI();
}
createUI() {
const viewer = this.viewer;
const rvtGroupPanel = new AdnRevitGroupPanel( viewer, 'Revit Group' );
viewer.addPanel( rvtGroupPanel );
this.panel = rvtGroupPanel;
const rvtGroupButton = new Autodesk.Viewing.UI.Button( 'toolbar-adnRevitGroupTool' );
rvtGroupButton.setToolTip( 'Revit Group' );
rvtGroupButton.setIcon( 'adsk-icon-properties' );
rvtGroupButton.onClick = function() {
rvtGroupPanel.setVisible( !rvtGroupPanel.isVisible() );
};
const subToolbar = new Autodesk.Viewing.UI.ControlGroup( 'toolbar-adn-tools' );
subToolbar.addControl( rvtGroupButton );
subToolbar.adnRvtGroupButton = rvtGroupButton;
this.subToolbar = subToolbar;
viewer.toolbar.addControl( this.subToolbar );
rvtGroupPanel.addVisibilityListener(function( visible ) {
if( visible )
viewer.onPanelVisible( rvtGroupPanel, viewer );
rvtGroupButton.setState( visible ? Autodesk.Viewing.UI.Button.State.ACTIVE : Autodesk.Viewing.UI.Button.State.INACTIVE );
});
}
load() {
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.viewer.addEventListener(
Autodesk.Viewing.TOOLBAR_CREATED_EVENT,
this.onToolbarCreated
);
}
return true;
}
unload() {
if( this.panel ) {
this.panel.uninitialize();
delete this.panel;
this.panel = null;
}
if( this.subToolbar ) {
this.viewer.toolbar.removeControl( this.subToolbar );
delete this.subToolbar;
this.subToolbar = null;
}
return true;
}
}
Autodesk.Viewing.theExtensionManager.registerExtension( 'Autodesk.ADN.RevitGroupPanel', AdnRevitGroupPanelExtension );
})();
viewer.loadExtension( 'Autodesk.ADN.RevitGroupPanel' );
Here is the snapshot:
As you certainly know, Forge is a fully generic CAD modelling environment.
Therefore, it mainly provides support for cross-domain CAD functionality.
The Revit grouping functionality that you seek is BIM specific and cannot be recreated in a useful manner for all domains in Forge.
There are numerous way that you can work around this.
Here are two main approaches you might want to consider:
Implement a Revit add-in to retrieve and export the grouping data and make it available to your Forge app
Implement an app in Forge Design Automation for Revit to gather the required data from the RVT hosted in Forge
I want to click a link with certain text using Puppeteer.
<a class="text-major ev-pick-this-event"
href="/cgi-bin/ncommerce3/SEGetEventInfo?ticketCode=GS%3AAMTX%3AHUSKERS%3ASLP2%3A&linkID=BQFN80-AMTX&shopperContext=&pc=&caller=&appCode=&groupCode=SLP&cgc=&dataAccId=129&locale=en_US&siteId=ev_BQFN80-AMTX">
HUSKERS - SLP2 - Ranges
</a>
It can be done with XPath's contains() and text() methods, for example:
const [link] = await page.$x('//a[contains(text(), "certain text")]') // returns an array, as the first element will be used it can be destructured
await link.click()
let click = await page.evaluate(() => {
try {
const getText = e => (e ? e.innerText.trim() : '')
let links = document.querySelectorAll('nav a')
for (let i = 0, n = links.length; i < n; i++) {
if (getText(links[i]) === 'Home') {
links[i].click()
return getText(links[i])
}
}
} catch (e) {
return e.toString()
}
})
console.log({ click })
I have a problem with changes of material of some elements
when geometry is loaded:
_this.viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT, () => {
changeModelMaterial()
});
...
const changeModelMaterial = () => {
const grey = new THREE.Color(0.5, 0.5, 0.5);
let dbIds = getDbIds()
changeAllElementsMaterial(grey)
setMaterialOfDbIds(dbIds)
}
code that i`m using to change material:
const changeAllElementsMaterial = (color) => {
const fragmentList = _this.viewer.model.getFragmentList();
for (let materialId of fragmentList.materialids) {
if (fragmentList.materialmap[materialId]) {
fragmentList.materialmap[materialId].map = null
fragmentList.materialmap[materialId].color = color
fragmentList.materialmap[materialId].needsUpdate = true;
}
}
_this.viewer.impl.invalidate(true);
}
const setMaterialOfDbIds = (dbIds) => {
var color_diffuse = 0xAB00EE;
var color_specular = 0xEEABEE;
var colorM = new THREE.MeshPhongMaterial({
color: color_diffuse,
specular: color_specular
});
_this.viewer.impl.matman().addMaterial(
'ADN-Material-' +
"common color material", // or a GUID
colorM,
true);
for (let dbId of dbIds) {
_this.viewer.model.getData().instanceTree.enumNodeFragments(dbId, function (fragId) {
_this.viewer.model.getFragmentList().setMaterial(fragId, colorM);
});
}
_this.viewer.impl.invalidate(true);
}
It works, because I see that materials of model are changed, but the problem is that materials back to default after ~1-2 sec.
After this I cannot change material even with run this code manually.
Question is why Viewer is locking material change after this 2 sec, how to prevent it
And maybe you will be able to tell me what i can do better with material changes, eg. maybe something better that running my code after GEOMETRY_LOAD. The best would be change material before first render of model
........
hint:
when change event from GEOMETRY_LOADED_EVENT to OBJECT_TREE_CREATED_EVENT "sometimes" but only sometimes it works well (materials stay to the end of working with model), but mostly when i run my method after OBJECT_TREE_CREATED it not working (even not working by run it manually, materials are in some way locked). So I suspect that problem is between time of GEOMETRY_LOAD and OBJECT_TREE_CREATED
I will be grateful for any help
==============================full code==============================
index.html
<div id="main">
<div id="MyViewerDiv"></div>
<button id="open-nav-button" onClick="showDocInfo()">test</button>
</div>
<script src="https://developer.api.autodesk.com/derivativeservice/v2/viewers/three.min.js"></script>
<script src="https://developer.api.autodesk.com/derivativeservice/v2/viewers/viewer3D.min.js"></script>
<script type="text/javascript" src="lib/jquery.min.js"></script>
<script src="js/autodesk-viewer.js"></script>
<script src="js/extension/test-extension.js"></script>
<script>
const autodeskViewer = new AutodeskViewer()
const showDocInfo = () => {
autodeskViewer.showDocInfo()
}
</script>
autodesk-viewer.js
var AutodeskViewer = (function () {
function AutodeskViewer() {
var _this = this;
this.urn = 'urn:dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6Zm9yZ2UtamF2YS1zYW1wbGUtYXBwLTFzcGduazdqcWpxdjhmYXV0YmNzd2R0cGdvN3VtNWY1L1BPQy1Gb3JnZS1JVCUyMDIwMTclMjBSdWNoXzEwMDUxNy5ud2Q';
this.initializeViewer = function (containerId, documentId) {
_this.viewerApp = new Autodesk.Viewing.ViewingApplication(containerId);
var config = {
extensions: ['TestExtension']
};
_this.viewerApp.registerViewer(_this.viewerApp.k3D, Autodesk.Viewing.Private.GuiViewer3D, config);
_this.viewerApp.loadDocument(documentId, _this.onDocumentLoadSuccess, _this.onDocumentLoadFailure);
}
this.onDocumentLoadSuccess = function (doc) {
const viewables = _this.viewerApp.bubble.search(av.BubbleNode.MODEL_NODE);
if (viewables.length === 0) {
return;
}
_this.viewerApp.selectItem(viewables[0].data, _this.onItemLoadSuccess, _this.onItemLoadFail);
_this.viewer3d = _this.viewerApp.getCurrentViewer();
}
this.onDocumentLoadFailure = (viewerErrorCode) => {}
this.onItemLoadSuccess = (viewer) => {
_this.viewer = viewer
}
this.onItemLoadFail = (errorCode) => {}
this.initialize = () => {
var options = {
env: 'AutodeskProduction',
getAccessToken: _this.getToken,
refreshToken: _this.getToken
};
Autodesk.Viewing.Initializer(options, _this.initCallback);
};
this.initCallback = function () {
_this.initializeViewer('MyViewerDiv', _this.urn, '3d');
};
this.getToken = function (onGetAccessToken) {
$.get("forge/oauth/token")
.done(function (data) {
token = data
onGetAccessToken(token, 60 * 60);
})
.fail(function (error) {
console.log('ERROR', error);
});
};
this.showDocInfo = function () {};
this.initialize();
}
return AutodeskViewer;
}());
test-extension.js
var _self;
var _viewer;
var _tempValue = 0;
function TestExtension(viewer, options) {
Autodesk.Viewing.Extension.call(this, viewer, options);
_self = this;
_viewer = viewer;
}
const changeModelMaterial = () => {
// _tempValue++;
// if (_tempValue == 2) {
const elements = [4340, 4342, 4344, 4346, 4348, 4367, 4371, 4375, 4380, 4452, 4468, 4488, 4503, 4517, 4520, 4522, 4524, 4526, 4528, 4530]
changeAllElementsMaterial(new THREE.Color(0.5, 0.5, 0.5))
setMaterialOfDbIds(elements)
_tempValue = 0
// }
}
const changeAllElementsMaterial = (color) => {
var fragmentList = _viewer.model.getFragmentList();
for (let materialId of fragmentList.materialids) {
if (fragmentList.materialmap[materialId]) {
fragmentList.materialmap[materialId].map = null
fragmentList.materialmap[materialId].color = color
fragmentList.materialmap[materialId].needsUpdate = true;
}
}
_viewer.impl.invalidate(true);
}
const setMaterialOfDbIds = (dbIds) => {
var colorM = new THREE.MeshPhongMaterial({
color: new THREE.Color(0xAB00EE)
});
for (let dbId of dbIds) {
_viewer.model.getData().instanceTree.enumNodeFragments(dbId, function (fragId) {
_viewer.model.getFragmentList().setMaterial(fragId, colorM);
});
}
_viewer.impl.invalidate(true);
}
TestExtension.prototype = Object.create(Autodesk.Viewing.Extension.prototype);
TestExtension.prototype.constructor = TestExtension;
TestExtension.prototype.load = function () {
_viewer.addEventListener(Autodesk.Viewing.OBJECT_TREE_CREATED_EVENT, changeModelMaterial)
// _viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT, changeModelMaterial)
return true
};
TestExtension.prototype.unload = function () {
return true
};
Autodesk.Viewing.theExtensionManager.registerExtension('TestExtension', TestExtension);
I found the solution, quite accidentally... from other thing i tried to do
before:
const setMaterialOfDbIds = (dbIds) => {
var color_diffuse = 0xAB00EE;
var color_specular = 0xEEABEE;
var colorM = new THREE.MeshPhongMaterial({
color: color_diffuse,
specular: color_specular
});
_this.viewer.impl.matman().addMaterial("common color material", colorM, true);
for (let dbId of dbIds) {
_this.viewer.model.getData().instanceTree.enumNodeFragments(dbId, function (fragId) {
_this.viewer.model.getFragmentList().setMaterial(fragId, colorM);
});
}
_this.viewer.impl.invalidate(true);
}
after
const setMaterialOfDbIds = (dbIds) => {
var color_diffuse = 0xAB00EE;
var color_specular = 0xEEABEE;
var colorM = new THREE.MeshPhongMaterial({
color: color_diffuse,
specular: color_specular
});
_this.viewer.impl.matman().addMaterial("common color material", colorM, true);
for (let dbId of dbIds) {
_this.viewer.model.getData().instanceTree.enumNodeFragments(dbId, function (fragId) {
_this.viewer.model.getFragmentList().setMaterial(fragId, colorM);
var fragProxy = _this.viewer.impl.getFragmentProxy(_this.viewer.model, fragId)
fragProxy.updateAnimTransform()
});
}
_this.viewer.impl.invalidate(true);
}
Really I don`t know why adding
var fragProxy = _this.viewer.impl.getFragmentProxy(_this.viewer.model, fragId)
fragProxy.updateAnimTransform()
made the difference, i didn`t saw anything like that in any example of updating material.
What is interesting this code is running for only few elements in model, but it works for even those elements that materials changed before (in changeAllElementsMaterial method).
#Philippe Leefsma if you understand it pls tell something more why it works
So far I cannot reproduce the issue on my side, I am using the following code (ES7) extracted from that extension: Viewing.Extension.Material
createColorMaterial (color) {
const material = new THREE.MeshPhongMaterial({
specular: new THREE.Color(color),
side: THREE.DoubleSide,
reflectivity: 0.0,
color
})
const materials = this.viewer.impl.getMaterials()
materials.addMaterial(
this.guid(),
material,
true)
return material
}
async onModelCompletedLoad() {
const material = this.createColorMaterial(0xFF0000)
const model = this.viewer.model
const fragIds = await Toolkit.getFragIds(model)
fragIds.forEach((fragId) => {
model.getFragmentList().setMaterial(
fragId, material)
})
this.viewer.impl.sceneUpdated(true)
}
The onModelCompletedLoad is a custom event fired when both GEOMETRY_LOADED_EVENT and OBJECT_TREE_CREATED_EVENT have been fired.
Take a look at this article for more details: Asynchronous viewer events notification
I doubt you can easily change the materials before the model is first rendered, however you could use a custom overlay that hides the model until your custom logic has performed all required steps, this is the approach I am using in my demos at: https://forge-rcdb.autodesk.io/configurator
After loading a model, all custom materials are being persisted fine:
The material extension can be tested live from there.
Hope that helps
When we isolate an element in a 3d view, is there anyway to control the amount of transparency of all the other elements? Say, change to 50% translucent?
Have I missed something obvious?
And can you do the same for 2d views?
I dug out the following code for you, it shows how to set all leaf nodes to 50% opacity by changing their material properties:
AutodeskNamespace("Autodesk.ADN.Viewing.Extension");
function getLeafNodes(model, nodeId) {
return new Promise((resolve, reject)=>{
try{
var leafIds = [];
var instanceTree = model.getData().instanceTree
nodeId = nodeId || instanceTree.getRootId()
function _getLeafNodesRec(id){
var childCount = 0;
instanceTree.enumNodeChildren(id,
function(childId) {
_getLeafNodesRec(childId)
++childCount
})
if(childCount == 0){
leafIds.push(id)
}
}
_getLeafNodesRec(nodeId)
return resolve(leafIds)
} catch(ex){
return reject(ex)
}
})
}
function nodeIdToFragIds(model, nodeId) {
var instanceTree = model.getData().instanceTree
var fragIds = []
instanceTree.enumNodeFragments(
nodeId, (fragId) => {
fragIds.push(fragId)
});
return fragIds
}
Autodesk.ADN.Viewing.Extension.Basic = function (viewer, options) {
Autodesk.Viewing.Extension.call(this, viewer, options);
var _this = this;
_this.load = function () {
var fragList = viewer.model.getFragmentList()
getLeafNodes(viewer.model).then((dbIds) => {
dbIds.forEach((dbId) => {
const fragIds = nodeIdToFragIds(
viewer.model, dbId)
fragIds.forEach((fragId) => {
var material = fragList.getMaterial(fragId)
if(material) {
material.opacity = 0.5
material.transparent = true
material.needsUpdate = true
}
})
})
viewer.impl.invalidate(true, true, true)
})
return true;
};
_this.unload = function () {
Autodesk.Viewing.theExtensionManager.unregisterExtension(
"Autodesk.ADN.Viewing.Extension.Basic");
return true;
};
};
Autodesk.ADN.Viewing.Extension.Basic.prototype =
Object.create(Autodesk.Viewing.Extension.prototype);
Autodesk.ADN.Viewing.Extension.Basic.prototype.constructor =
Autodesk.ADN.Viewing.Extension.Basic;
Autodesk.Viewing.theExtensionManager.registerExtension(
"Autodesk.ADN.Viewing.Extension.Basic",
Autodesk.ADN.Viewing.Extension.Basic);
Some syntax requires ES6 transpiling. You can quickly paste the code there to test it: http://viewer.autodesk.io/node/gallery/#/extension-editor?id=560c6c57611ca14810e1b2bf
This works only for 3D, I'll see what we can do for 2D and update that topic.