How to create a custom button pressable on HoloLens device?
We can create a customer button/button panel on HoloLens performing the following steps:
Create a model with button and panel / it could be a panel with more buttons. In this example I used Creo Parametric for the 3d model creation – I estimated for this sample model I needed 30 – 60 Minutes .
The assembly above consist of 3 parts, panel and button. The panel is a part with a pattern of hole feature - in case that we need a circular button. If we need a button with other shape we could use a pattern of cut features
Here in this example I created a button which is circular and has a text which is a cut of the top surface. To have a different button’s I created a family table where a parameter for the text was added. I used the parameter in a relation to change the text in the cut.
Later I added the panel in a new component as default placement and added to each hole feature a button as repeat component. After all components are added to the assembly (the generic part) we can replace each component (the generic part - the part which defines the family table) by the family table instance - so to have a buttons with different texts. Above we can see in the picture that in the instance "BUTTON3D_15" we have the value “BN15” for the parameter BNTTXT which is displayed in the button text.
I attached the assembly (created in Creo Parametric 6.0). You can open the button part (button3d.prt) and edit the family table - the values of the parameter BNTTXT - to have other text values for the different buttons. Then you need to verify and to regenerate the part. Please, pay attention, that the text should be should be not so long , because the button top surface is small
The last point here is to export /save as / the assembly to pvz format
2.) Create a Vuforia Studio project for HoloLens device. For the button panel we need to add a new modelWidget and for each button we can define a modelItem widget:
To make the project now to work we need to define a JavaScript code. Here the code is define in the Home.js
define the callback function for the click on a button event/action:
//============================================================
$scope.app.clickButton= function(target) //work of ModelItem widgets
{
var zDelta=0.035
var buttonReactionTime=1.2
if($scope.view.wdg[target.toString()].opacity==0.8) return; //ignorre the double click
if(!target.toString().startsWith("bnt"))
{console.log("not bnt button");return;}
//extracts only the number of the string
var btnNr= parseInt(target.toString().replace(/bnt/g,''));
console.log("btnNr="+btnNr)
var currZvalue=$scope.view.wdg[target.toString()].z +zDelta
console.log("1.).currZvalue="+currZvalue)
$scope.setWidgetProp( target,"z",currZvalue)
$scope.setWidgetProp( target, 'color', "rgba(255,0,0,1.0)")
$scope.setWidgetProp( target, 'opacity', 0.8)
$scope.$applyAsync();
$timeout(()=>{
currZvalue=$scope.view.wdg[target.toString()].z -zDelta
console.log("2.).currZvalue="+currZvalue)
$scope.setWidgetProp( target,"z",currZvalue)
$scope.setWidgetProp( target, 'color', "rgba(3,255,22,1.0)")
$scope.setWidgetProp( target, 'opacity',0.4 )
$scope.setWidgetProp( "3DLabel-1", 'text', $scope.view.wdg["3DLabel-1"].text+btnNr)
$scope.$applyAsync();
},buttonReactionTime*1000)
}
//============================================================
In this function we have as input the target / this is the modelItem widget clicked - here the button/. The function will move the button in Z direction , will change it's color and will add the button text to a label /some kind as input/. After some delay it will move the button back and will set the color to the old value
The next definition is the definition of the listener which will handle the button click and will call the button callback function for the clicked item:
//============================================================
$scope.userpickDef= function() {
// define the button action
document.addEventListener('userpick', function (ev) {
var widget = ev.target.closest('twx-widget');
if (widget) {
console.log('*->the widget clicked is ', widget.getAttribute('widget-id'));
$scope.app.clickButton(widget.getAttribute('widget-id').toString())
}
else {
var widget = twx.app.getScope(ev.target);
if (widget) {
console.log('**->the widget clicked is ', widget._widgetId, widget);
$scope.app.clickButton( (widget._widgetId).toString())
}
}
});
};
//============================================================
finally we need to add a setup code which we could call e.g. on modelLoad event:
$rootScope.$on("modelLoaded", function() {
$scope.view.wdg['btnPanel'].shader = "xray";
$scope.view.wdg['btnPanel'].occlude = 0.2;
for(var i=1 ; i<=15; i++)
{
var wdgName = "bnt"+i.toString();
$scope.setWidgetProp( wdgName, 'color', "rgba(3,255,22,1.0)")
$scope.setWidgetProp( wdgName, 'opacity', 0.4)
}
$scope.$applyAsync();
$scope.userpickDef();
});
Here we could set the opacity and the color of all buttons and define the button click listener.
I added to this post the Creo Parametric Assembly model, the panel model as pvz and the demo project.
View full tip