Evidenziare gli elementi selezionati
1. Per fornire un feedback visivo chiaro all'utente in fase di esecuzione, la selezione di un sottoassieme o di una parte nel modello dovrebbe attivare un indicatore visivo. Ciò consente agli utenti di confermare che stanno visualizzando i dati dell'elemento corretto. A tale scopo, applicheremo lo shader highlight all'elemento del modello selezionato. Aggiungere quanto segue al file Visualization.js:
// call this function to highlight the list of selected parts
//
var highlightParts = (selectedList, modelId) => {
var highlightedList = [];
// run over all the items in the list and assign the highlight shader
selectedList.forEach( (partId) => {
var renderingPartId = modelId + "-" + partId;
var shader = "highlight;r f 1;g f 0.5;b f 0.25;a f 1" + (twx.app.isPreview() ? ";virtualMode f 1.0":"");
tml3dRenderer.setProperties(renderingPartId, { shader: shader, opacity: 1.0, hidden: false });
// and keep a record of what we highlighted - so that we wan undo it later
//
highlightedList.push(renderingPartId);
});
return highlightedList;
}
2. Inoltre, quando l'utente fa clic per uscire da un sottoassieme precedentemente selezionato o ne seleziona un altro, lo shader highlight deve essere aggiornato di conseguenza. Ciò garantisce che solo l'elemento attualmente selezionato rimanga evidenziato visivamente, garantendo chiarezza in tutta l'interazione. Pertanto, è necessario aggiungere anche quanto segue al file Visualization.js:
// call this function to clear the highlights
//
var highlightReset = (highlightedList) => {
// run over all the items in the list and unsasign the shader
//
highlightedList.forEach( (modelIdpartId) => {
tml3dRenderer.setProperties(modelIdpartId,{ shader:"", opacity: 0.2, hidden: !twx.app.isPreview() });
});
return [];
}
3. A questo punto, quando un utente seleziona un elemento dall'elenco parti, tale elemento deve essere evidenziato. Prestare particolare attenzione alla logica utilizzata nel seguente snippet di codice, soprattutto se si utilizza un modello personalizzato. La logica si basa su attributi che devono essere definiti e disponibili in Creo Illustrate e caricati in fase di esecuzione per ogni parte. Se si utilizzano una chiave diversa o attributi personalizzati per visualizzare i dati specifici di una parte, assicurarsi di aggiornare di conseguenza i riferimenti agli attributi nel codice seguente in modo che corrispondano alla struttura del modello nel file Visualization.js:
// used to track which items are highlighted
$scope.lit = [];
// called when the user taps on a property in the named list, or taps on a part in the view - this changes the 'current' field
//
$scope.$watch(
() => {
return ($scope.view.wdg.partsList.list != undefined &&
$scope.view.wdg.partsList.list.current != undefined) ? JSON.stringify($scope.view.wdg.partsList.list.current) : "";
},
//value == 'currentSelectedPart',
(value) => {
highlightReset($scope.lit);
var partNumber = JSON.parse(value);
// first of all, lets get all the metadata values for this selected item
//
var plist = [];
PTC.Metadata.fromId(partNumber.model)
.then ( (metadata) => {
// find all the items with this partnumber
//
plist = metadata.find(metadataKey).like(partNumber.name);
if (plist == undefined)
{
return;
}
// highlight those items
//
$scope.lit = highlightParts(plist.getSelected(), partNumber.model);
// now find some interesting properties
//
var interestingProperties = ["cost","supplier","weight","partNumber"];
// this function (declared inline) is used to get the property values (see above) for eeach of the items
// in the previously acquired partnmubered plist - it will iterate through each item (idpath) and get the
// properties for each item; if found, they are captured into an array of name=value pairs.
//
var getInteresting = (ip) => {
var ilist = ip;
return function(idpath) {
const res = this.get(idpath, ilist);
var retobj = { path:idpath };
if (res != undefined && res.length === ilist.length) for (var p=0;p<ilist.length;p++) {
// add each result as a new property in the return body
retobj[ilist[p]] = res[p];
}
return retobj;
}
}
// get a list of items with this property set
//
plist = plist.getSelected(getInteresting(interestingProperties));
// helper function to get and format the properties - this generates a list of name|value pairs
//
var getNameValues = (items) => {
var nv = [];
items.forEach( (i) => {
Object.keys(i).forEach( (j) =>{
if (interestingProperties.includes(j)) nv.push({name:j, value:i[j]});
})
})
return nv;
}
// we need to turn this into a list of item/name/value
//
$scope.view.wdg.propertiesList.data = getNameValues(plist);
//
// and show the popup
//
twx.app.fn.triggerWidgetService("propertyPopup", 'showpopup')
})
}
);
4. Nei casi in cui l'utente non disponga del nome o dell'ID specifico di una parte, può selezionare interattivamente il sottoassieme pertinente direttamente nel modello. Per questo scenario, aggiungere quanto segue:
// called if the user taps on a part
$scope.$on("userpick", (event, model, type, args) => {
PTC.Metadata.fromId(model)
.then ( (metadata) => {
var pathId = JSON.parse(args).occurrence;
var sid = metadata.get(pathId, metadataKey);
var findMetaDataKey = (p) => {
// simple inline closure that will test if the item name is the value specificed (p in this case)
// this gets called for all items in the list (see findIndex, below)
//
return function(v) { return v.name == p; }
}
// work out which row we need to select
//
var fid = $scope.view.wdg.partsList.list.findIndex(findMetaDataKey(sid));
// return call here if not found
// ... and mark it as selected
//
$scope.view.wdg.partsList.list.forEach( (v,i) => { v._isSelected = (i == fid) });
// and get the row to highlight in 3d
//
$scope.view.wdg.partsList.list.current = $scope.view.wdg.partsList.list.filter( (v,i) => { return i == fid })[0];
})
});