Community Tip - You can change your system assigned username to something more personal in your community settings. X
Dear Sir or Madam,
We are currently working on our diploma thesis together with the school and a company. For our diploma thesis, we are creating assembly instructions in Creo Illustarte to train a worker. These instructions are displayed to the worker with a HoloLens. Therefor we are using Vuforia Studio to display Buttons etc.
We need the Wayfinder widget so we can set waypoints, to let the worker know where he needs to look. Our problem is that we want to show or hide a specific waypoint using a virtual button (in the future, this virtual button will be replaced by a Thingworx parameter - real button).
In addition, we want to know how to play a certain sequence right after the employee has found the waypoint. Could you tell us how to get acces to a specific Waypoint? So we can show or hide a specific waypoint after receiving a true or false from ThingWorx and play a specific Sequence right after finding/arriving to the Waypoint.
We need a Java Script code or other solutions for both cases.
I hope you can help us with this! Thanks in advance!
Solved! Go to Solution.
Hi Roland,
I would like to briefly describe what my students are dealing with and where we still have problems.
My students have designed and built an assembly workstation where various battery housings are to be assembled.
In order to train employees at this assembly workplace, an AR experience was created for the HoloLens.
The playback of the individual work steps (one after the other) is controlled via Thingworx parameters.
These parameters in Thingworx (Industrial Thing - Industrial Connection) are controlled via Kepware by a PLC Siemens C1215C.
Sensors check which battery housings are being delivered or need to be assembled and whether the work steps have been carried out correctly.
We also want to show waypoints for specific work steps.
The housings are delivered to the lefthand side of the worker - here we want to display a waypoint.
The worker then places the finished housing on the right side of the conveyor belt - we also want to display a waypoint there.
No waypoint should be displayed during the other work steps.
I tried the following code on a simple example:
Language selection: By clicking on the button, the language is set to German or English (with the variable lang2)
var lang2 = 'deu';
$scope.onSprachauswahl_Pressed = function() {
lang2 = 'deu';
$scope.app.view['Home'].wdg['3DLabel-lang2']['text'] = lang2;
};
$scope.onSprachauswahl_Unpressed = function() {
lang2 = 'eng';
$scope.app.view['Home'].wdg['3DLabel-lang2']['text'] = lang2;
};
At the beginning, the Wayfinder widget is deactivated via the application parameter "enable_wayfinder" which controls the property "Enabled".
$scope.app.params.enable_wayfinder = false;
If the parameter "Gehaeuse_VS" is "true" controlled via Thingworx, waypoint 2 (Waypointndex = 1) should be displayed and when reached
(Waypoint_arrived) a text is displayed depending on the language selection and a sound file and then a sequence (not entered here) is played.
$scope.$watch("app.params['Gehaeuse_VS']", function() {
if ($scope.app.params.Gehaeuse_VS == 'true') {
$scope.setWidgetProp('wayfinder-1','selectedWaypointIndex',1)
$scope.app.params.enable_wayfinder = true;
$scope.Waypoint_arrived = function() {
if (lang2 == 'deu') {
$scope.app.view['Home'].wdg['3DLabel-Textanzeige']['text'] = "Gehäuse von links einbauen!";
} else {
$scope.app.view['Home'].wdg['3DLabel-Textanzeige']['text'] = "Assembly the Battery housing from the left side!";
}
$scope.app.params.enable_wayfinder = false;
var soundFilePath = "app/resources/Uploaded/Gehaeuse_" + lang2 + ".mp3";
var audio = new Audio(soundFilePath);
$timeout(function() {
audio.play();
}, 500);
}
}
});
In the Preview this works so far, but at the end the Wayfinder widget is not deactivated again but rather remains displayed and active.
However, it works on HoloLens2.
The following step is one without a waypoint, controlled via the parameter “Deckel_VS”, again via Thingworx.
$scope.$watch("app.params['Deckel_VS']", function() {
if ($scope.app.params.Deckel_VS == 'true') {
if (lang2 == 'deu') {
$scope.app.view['Home'].wdg['3DLabel-Textanzeige']['text'] = "Deckelmontage, Aufschrift PIA Automation muß sichtbar sein!";
} else {
$scope.app.view['Home'].wdg['3DLabel-Textanzeige']['text'] = "Install the cover, PIA Automation label must be visible.";
}
var soundFilePath = "app/resources/Uploaded/Deckel_" + lang2 + ".mp3";
var audio = new Audio(soundFilePath);
$timeout(function() {
audio.play();
}, 500);
}
});
In this step, waypoint 1 should be displayed with Waypointindex = 0 and should be deactivated again after arriving waypoint 1
$scope.$watch("app.params['Akkuzelle_VS']", function() {
if ($scope.app.params.Akkuzelle_VS == 'true') {
$scope.setWidgetProp('wayfinder-1','selectedWaypointIndex',0)
$scope.app.params.enable_wayfinder = true;
$scope.Waypoint_arrived = function() {
if (lang2 == 'deu') {
$scope.app.view['Home'].wdg['3DLabel-Textanzeige']['text'] = "Akkuzelle an der richtigen Position platzieren!";
} else {
$scope.app.view['Home'].wdg['3DLabel-Textanzeige']['text'] = "Place the battery cell in the correct position.";
}
$scope.app.params.enable_wayfinder = false;
var soundFilePath = "app/resources/Uploaded/Akkuzelle_" + lang2 + ".mp3";
var audio = new Audio(soundFilePath);
$timeout(function() {
audio.play();
}, 500);
}
}
});
Here again, the wayfinder widget is not deactivated in the preview and rather remains active and the waypoint is displayed, however it works on HoloLens2.
The Preview:
On HoloLens2:
I hope the code above fits our needs.
Thanks for the quick answers.
Hi @armink,
to the one question in your topic - here about the automatic play of steps when you arrive a waypoint here an example
So this example has a model with a sequence TestFig which have 12 steps. So there are also a wayfinder widget with 12 waypoints for each step there is a point (in this is an example the postions of the waypoints are not really relevant here ... acctually they do not make sense - it is only as example) so when you go to a point then it will paly the step with the same number . Also you could rewind or forward both - waypoints or steps. Here the example
I hope helps. BR
@armink to your second question in your post /topic:
###############
Similar to the the example what I already uploaded in the previous post - showing the automatic play of steps when you arrive a waypoint .
I removed all waypoints , where I saved the waypointsData property of the wayfinder widget example:
the data contained by waypointsData is a json array and could be modifed or created by javscript functions.
I removed all way points from the wayfinder widgets so that when starting the widget - there are no acctually any waypoints. Then set the property waypointsData with the json array and all waypoints are defined. So this means that you dynamicaly define the waypoints.
Example:
//##########################################
//// here the waitpoint data for 16 Waypoints
/// this could be prepared as template
/// depending on this hwo many points you want to use
//######################################
$scope.app.waypointsdata=[{"position":{"x":-0.5,"y":0.5,"z":0},"gaze":{"x":0,"y":0,"z":-1},"up":{"x":0,"y":1,"z":0},"eventRadius":"0.2","wayfinderDisplayBoundary":"0.2","label":"Waypoint 1"},{"position":{"x":0.0608,"y":0.4892,"z":0},"gaze":{"x":0,"y":0,"z":-1},"up":{"x":0,"y":1,"z":0},"eventRadius":"0.2","wayfinderDisplayBoundary":"0.2","label":"Waypoint 2"},{"position":{"x":0.5117,"y":0.6721,"z":-0.3123},"gaze":{"x":0,"y":0,"z":-1},"up":{"x":0,"y":1,"z":0},"eventRadius":"0.2","wayfinderDisplayBoundary":"0.2","label":"Waypoint 3"},{"position":{"x":-0.1058,"y":0.6174,"z":0.1117},"gaze":{"x":0,"y":0,"z":-1},"up":{"x":0,"y":1,"z":0},"eventRadius":"0.2","wayfinderDisplayBoundary":"0.2","label":"Waypoint 4"},{"position":{"x":-0.1467,"y":0.1608,"z":0.1022},"gaze":{"x":-5.781425897883269e-17,"y":0.47208925070547064,"z":0.8815507582484104},"up":{"x":0,"y":1,"z":0},"eventRadius":"0.2","wayfinderDisplayBoundary":"0.2","label":"Waypoint 5"},{"position":{"x":0,"y":0,"z":0},"gaze":{"x":0,"y":0,"z":-1},"up":{"x":0,"y":1,"z":0},"eventRadius":0.25,"wayfinderDisplayBoundary":"1","label":"Waypoint 6"},{"position":{"x":1.0684,"y":0,"z":0.2729},"gaze":{"x":0,"y":-0.9999999847691291,"z":-0.00017453292431324208},"up":{"x":0,"y":1,"z":0},"eventRadius":0.25,"wayfinderDisplayBoundary":"1","label":"Waypoint 7"},{"position":{"x":0,"y":0,"z":0},"gaze":{"x":0,"y":0,"z":-1},"up":{"x":0,"y":1,"z":0},"eventRadius":0.25,"wayfinderDisplayBoundary":"1","label":"Waypoint 8"},{"position":{"x":0,"y":0,"z":0},"gaze":{"x":0,"y":0,"z":-1},"up":{"x":0,"y":1,"z":0},"eventRadius":0.25,"wayfinderDisplayBoundary":"1","label":"Waypoint 9"},{"position":{"x":0,"y":0,"z":0},"gaze":{"x":0,"y":0,"z":-1},"up":{"x":0,"y":1,"z":0},"eventRadius":0.25,"wayfinderDisplayBoundary":"1","label":"Waypoint 10"},{"position":{"x":0.5752,"y":0,"z":0.6409},"gaze":{"x":0,"y":-0.9999999847691291,"z":-0.00017453292431324208},"up":{"x":0,"y":1,"z":0},"eventRadius":0.25,"wayfinderDisplayBoundary":"1","label":"Waypoint 11"},{"position":{"x":0,"y":0,"z":0},"gaze":{"x":0,"y":0,"z":-1},"up":{"x":0,"y":1,"z":0},"eventRadius":0.25,"wayfinderDisplayBoundary":"1","label":"Waypoint 12"},{"position":{"x":0.4452,"y":0,"z":0.3125},"gaze":{"x":0,"y":-0.9999999847691291,"z":-0.00017453292431324208},"up":{"x":0,"y":1,"z":0},"eventRadius":0.25,"wayfinderDisplayBoundary":"1","label":"Waypoint 13"},{"position":{"x":-0.071,"y":0,"z":0.9664},"gaze":{"x":0,"y":-0.9999999847691291,"z":-0.00017453292431324208},"up":{"x":0,"y":1,"z":0},"eventRadius":0.25,"wayfinderDisplayBoundary":"1","label":"Waypoint 14"},{"position":{"x":-0.1722,"y":0,"z":1.1677},"gaze":{"x":0,"y":-0.9999999847691291,"z":-0.00017453292431324208},"up":{"x":0,"y":1,"z":0},"eventRadius":0.25,"wayfinderDisplayBoundary":"1","label":"Waypoint 15"},{"position":{"x":0,"y":0,"z":0},"gaze":{"x":0,"y":0,"z":-1},"up":{"x":0,"y":1,"z":0},"eventRadius":0.25,"wayfinderDisplayBoundary":"1","label":"Waypoint 16"}];
//######################################
//######the function below is called e.g. by button
// or at the moment when you want to change the
//way point configuration
//######################################
$scope.app.setWayFinderData=()=>{
//set the wayfinder-1 data of the points
for(let count=0; count < $scope.app.waypointsdata.length;count++)
$scope.app.waypointsdata[count].position.z -=0.5 ; //increments all z with -0.5
$timeout(()=>{
$scope.setWidgetProp('wayfinder-1' ,'waypointsData',$scope.app.waypointsdata);
$scope.$applyAsync();
},300)//called with some delay 0.3 sec
}
//######################################
So saved the waypoint data as array - this array could be used as template and retrieved e.g. as JSON object from a Thingworx service
Change there something - here in example increment all z values of the waypoints with -0.5
set the data - so far my test this worked fine.
Attached also the test example // see button "activate_waitPoints" which calls onClick "app.setWayFinderData();"
First of all, thank you for the extensive answers, I really appreciate that!
The codes you sent me are helpful but are way too complex for my needs... .I attached You photos of my codes and the current situation of my Vuforia Studio project.
The label ("There are not enough lids...") you see above the language button would be replaced by a waypoint (with the corresponding text) which is placed on the left-hand euro crate later on... . My question now is how to solve it, so that the sequence is played when I get into the radius of the waypoint and how to show and hide them in a specific sequence.
Thanks in advance!
Hi @armink ,
following points: when you try to check in a $watch construct a different variables - so the question is - what is the mean intent there?
I see that you added external services there - so if I understand this correctly you are checking different services and depending on that you want to decide what of modelWidget /sequence/ step should be played.
This could be difficult to by syncronized. Let say TWX will change the values all at the same time etc. So when you have implemented already all the program logic in thingworx then you can simple provide only one service which will return one object /INFOTABLE with pvi, step modelwidget so that on service on Vuforia Side could play this.
So the second point is there how to integrate the waypoint widget in the context of the existing widgets and js code.
So setting a waypoint widget you have to define the points and then depending to point what you arrive or departed you have to check what to do there so that example is nearly to the minimal implimentation
Hi Roland,
I would like to briefly describe what my students are dealing with and where we still have problems.
My students have designed and built an assembly workstation where various battery housings are to be assembled.
In order to train employees at this assembly workplace, an AR experience was created for the HoloLens.
The playback of the individual work steps (one after the other) is controlled via Thingworx parameters.
These parameters in Thingworx (Industrial Thing - Industrial Connection) are controlled via Kepware by a PLC Siemens C1215C.
Sensors check which battery housings are being delivered or need to be assembled and whether the work steps have been carried out correctly.
We also want to show waypoints for specific work steps.
The housings are delivered to the lefthand side of the worker - here we want to display a waypoint.
The worker then places the finished housing on the right side of the conveyor belt - we also want to display a waypoint there.
No waypoint should be displayed during the other work steps.
I tried the following code on a simple example:
Language selection: By clicking on the button, the language is set to German or English (with the variable lang2)
var lang2 = 'deu';
$scope.onSprachauswahl_Pressed = function() {
lang2 = 'deu';
$scope.app.view['Home'].wdg['3DLabel-lang2']['text'] = lang2;
};
$scope.onSprachauswahl_Unpressed = function() {
lang2 = 'eng';
$scope.app.view['Home'].wdg['3DLabel-lang2']['text'] = lang2;
};
At the beginning, the Wayfinder widget is deactivated via the application parameter "enable_wayfinder" which controls the property "Enabled".
$scope.app.params.enable_wayfinder = false;
If the parameter "Gehaeuse_VS" is "true" controlled via Thingworx, waypoint 2 (Waypointndex = 1) should be displayed and when reached
(Waypoint_arrived) a text is displayed depending on the language selection and a sound file and then a sequence (not entered here) is played.
$scope.$watch("app.params['Gehaeuse_VS']", function() {
if ($scope.app.params.Gehaeuse_VS == 'true') {
$scope.setWidgetProp('wayfinder-1','selectedWaypointIndex',1)
$scope.app.params.enable_wayfinder = true;
$scope.Waypoint_arrived = function() {
if (lang2 == 'deu') {
$scope.app.view['Home'].wdg['3DLabel-Textanzeige']['text'] = "Gehäuse von links einbauen!";
} else {
$scope.app.view['Home'].wdg['3DLabel-Textanzeige']['text'] = "Assembly the Battery housing from the left side!";
}
$scope.app.params.enable_wayfinder = false;
var soundFilePath = "app/resources/Uploaded/Gehaeuse_" + lang2 + ".mp3";
var audio = new Audio(soundFilePath);
$timeout(function() {
audio.play();
}, 500);
}
}
});
In the Preview this works so far, but at the end the Wayfinder widget is not deactivated again but rather remains displayed and active.
However, it works on HoloLens2.
The following step is one without a waypoint, controlled via the parameter “Deckel_VS”, again via Thingworx.
$scope.$watch("app.params['Deckel_VS']", function() {
if ($scope.app.params.Deckel_VS == 'true') {
if (lang2 == 'deu') {
$scope.app.view['Home'].wdg['3DLabel-Textanzeige']['text'] = "Deckelmontage, Aufschrift PIA Automation muß sichtbar sein!";
} else {
$scope.app.view['Home'].wdg['3DLabel-Textanzeige']['text'] = "Install the cover, PIA Automation label must be visible.";
}
var soundFilePath = "app/resources/Uploaded/Deckel_" + lang2 + ".mp3";
var audio = new Audio(soundFilePath);
$timeout(function() {
audio.play();
}, 500);
}
});
In this step, waypoint 1 should be displayed with Waypointindex = 0 and should be deactivated again after arriving waypoint 1
$scope.$watch("app.params['Akkuzelle_VS']", function() {
if ($scope.app.params.Akkuzelle_VS == 'true') {
$scope.setWidgetProp('wayfinder-1','selectedWaypointIndex',0)
$scope.app.params.enable_wayfinder = true;
$scope.Waypoint_arrived = function() {
if (lang2 == 'deu') {
$scope.app.view['Home'].wdg['3DLabel-Textanzeige']['text'] = "Akkuzelle an der richtigen Position platzieren!";
} else {
$scope.app.view['Home'].wdg['3DLabel-Textanzeige']['text'] = "Place the battery cell in the correct position.";
}
$scope.app.params.enable_wayfinder = false;
var soundFilePath = "app/resources/Uploaded/Akkuzelle_" + lang2 + ".mp3";
var audio = new Audio(soundFilePath);
$timeout(function() {
audio.play();
}, 500);
}
}
});
Here again, the wayfinder widget is not deactivated in the preview and rather remains active and the waypoint is displayed, however it works on HoloLens2.
The Preview:
On HoloLens2:
I hope the code above fits our needs.
Thanks for the quick answers.
thanks for the very detailed feedback and explanation! Really cool. I need some time to check it more detailed and will try to adapt the example.
Hi @ptc-1155647
as I mentioned in my last replay I wanted to chek your project . I see that this topic is spedified already as solution so there is not further requirment to add something else...
But after checking your project still I want to mention some points what I think that could lead to some improvments on your solution approuch :
- having a lot of external data entieties and then binding them to parmeters could be very difficult for furhter changing (extending) and maintaining of the project in the future time. So I tested with the set what you provided with this proejct and for me for this number 25 it was diffiuclt for me the have always an overview about the control structure. So possibly when you add the next Kepware measure/resplectively a TWX entity which will change you value dyncamicaly - then addiing a binding to an applicaiton parameter all this you need to check very detailed to ensure not run into an error.. Also later you need according to the projectdesign to add a $watch case for this where you will handle you parameter. Also you need to know e.g. what of pvi sequence should it play etc.
In the example you have 25 entities and you need 25 bindings and 25 $watch elements in the home.js. But what will be the situation when you over 100 elements or more. Therefore possibly you need to handle the data in Thingworx at all and to provide only the data with value , changed property name and structure what should be handled - e.g. pvi name and the waypont structure - as json. I pointed to such techniques in the previous post /example in this topic.
So another option what could be better possibly as the current design is to use a $watch array , where you create the array first dynamicaly ... example as approach:
so firther I did tested the issue with the current number of 25 parameters comming form Thingworx (TWX). I did change the property in TWX as simulation by 10 seconds timer and service which randomly selected one of the entities and set its property to true (all other are false) some think like this:
Also you can outsource some of your data to tWX or to json file and load them then on run time via some construct like this:
$http.get('app/resources/Uploaded/myBinding.json')
.success(function(data, status, headers, config) {//-------- success fnc
//console.warn(data)
$scope.app.myBinding=JSON.parse(JSON.stringify(data))
})//-------- end success fnic
.error(function(data, status, headers, config) { console.log("problem in myBinding ");});
$http.get('app/resources/Uploaded/steuerDaten.json')
.success(function(data, status, headers, config) {//-------- success fnc
//console.warn(data)
$scope.app.steuerDaten=JSON.parse(JSON.stringify(data))
})//-------- end success fnic
.error(function(data, status, headers, config) { console.log("problem in myBinding ");});
$timeout(() =>{
$http.get('app/resources/Uploaded/wayFinder.json')
.success(function(data, status, headers, config) {//-------- success fnc
//console.warn(data)
$scope.app.wayFinder=JSON.parse(JSON.stringify(data))
$scope.app.wayFinderArray=[]
let thngName="601457_5AHMBS_Sedik_PIA_Bulme_IndThing"
//------------- the wayFinder is json with keys but I need an array for the
//----way point data creating an array with the same data
for( let key in $scope.app.myBinding){
// console.log("key = ",key)
$scope.app.wayFinderArray.push($scope.app.wayFinder[$scope.app.myBinding[key]])
}
//console.log("$scope.app.wayFinderArray");console.warn($scope.app.wayFinderArray);
$timeout(()=>{ //---- set the wayfiner datat to widget data
$scope.setWidgetProp('wayfinder-1' ,'waypointsData',$scope.app.wayFinderArray);
$scope.$applyAsync(); },300)
})//-------- end success fnic
.error(function(data, status, headers, config) {console.log("problem in wayFinder ");});
},1000) //adding furhter delay
here example how in this case json structure could look like: (sample file steuerDaten.json)
{
"UE_Kiste_Deckel_li_VS" : {"en":{"text":"There are not enough lids in the left-hand Euro crate!","pvi":"","avi":"app/resources/Uploaded/02_Eurokiste_Deckelmenge.mp3","play":true},
"de":{"text":"In der linken Eurokiste sind nicht genügend Deckel vorhanden!","pvi":"","avi":"app/resources/Uploaded/02_Eurokiste_Deckelmenge.mp3","play":true}},
"UE_Kiste_Deckel_li_VS1" : {"en":{"text":"There are not enough lids in the left-hand Euro crate!","pvi":"app/resources/Uploaded/l-Creo 3D - UE_5FKiste_5FDeckel_5Fli.pvi","avi":"","play":true},
"de":{"text":"In der linken Eurokiste sind nicht genügend Deckel vorhanden!","pvi":"app/resources/Uploaded/l-Creo 3D - UE_5FKiste_5FDeckel_5Fli.pvi","avi":"","play":true}},
"UE_FB_li_VS" : {"en":{"text":"Text for UE_FB_li_VS en","pvi":"app/resources/Uploaded/l-Creo 3D - UE_5FFB_5Fli.pvi","avi":"","play":true},
"de":{"text":"-Text for UE_FB_li_VS in Deutsch","pvi":"app/resources/Uploaded/l-Creo 3D - UE_5FFB_5Fli.pvi","avi":"","play":true}},
"UE_Einlegeplatte_zuruecklegen_VS" : {"en":{"text":"english text for UE_Einlegeplatte_zuruecklegen_VS","pvi":"app/resources/Uploaded/l-Creo 3D - UE_5FEinlegeplatte_5Fzuruecklegen.pvi","avi":"","play":true},
"de":{"text":"Deutscher Text für UE_Einlegeplatte_zuruecklegen_VS","pvi":"app/resources/Uploaded/l-Creo 3D - UE_5FEinlegeplatte_5Fzuruecklegen.pvi","avi":"","play":true}},
"UE_Einlegeplatte_VS" : {"en":{"text":"english text for UE_Einlegeplatte_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Akkupack_5Fweglegen_5F4.pvi","avi":"","play":true},
"de":{"text":"Deutscher Text für UE_Einlegeplatte_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Akkupack_5Fweglegen_5F4.pvi","avi":"","play":true}},
"Akkupack_weglegen_4_VS" : {"en":{"text":"English Text for Akkupack_weglegen_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Akkupack_5Fweglegen_5F4.pvi","avi":"","play":true},
"de":{"text":"Deutsche Text für Akkupack_weglegen_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Akkupack_5Fweglegen_5F4.pvi","avi":"","play":true}},
"Akkupack_weglegen_6_VS" : {"en":{"text":"english text for Akkupack_weglegen_6_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Akkupack_5Fweglegen_5F6.pvi","avi":"","play":true},
"de":{"text":"Deutsche Text für Akkupack_weglegen_6_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Akkupack_5Fweglegen_5F6.pvi","avi":"","play":true}},
"UE_Schraubendreher_VS" : {"en":{"text":"english text for UE_Schraubendreher_VS","pvi":"app/resources/Uploaded/l-Creo 3D - UE_5FSchraubendreher.pvi","avi":"","play":true},
"de":{"text":"deutscher Text für UE_Schraubendreher_VS","pvi":"app/resources/Uploaded/l-Creo 3D - UE_5FSchraubendreher.pvi","avi":"","play":true}},
"Einlegeplatte_einlegen_4_VS" : {"en":{"text":"english text for Einlegeplatte_einlegen_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Einlegeplatte_5Feinlegen_5F4.pvi","avi":"","play":true},
"de":{"text":"deutscher Text für Einlegeplatte_einlegen_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Einlegeplatte_5Feinlegen_5F4.pvi","avi":"","play":true}},
"Gehaeuse_einlegen_4_VS" : {"en":{"text":"english text for Gehaeuse_einlegen_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Gehaeuse_5Feinlegen_5F4.pvi","avi":"","play":true},
"de":{"text":"deutscher Text für Gehaeuse_einlegen_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Gehaeuse_5Feinlegen_5F4.pvi","avi":"","play":true}},
"Zelleneinbau_1_VS" : {"en":{"text":"english text for Zelleneinbau_1_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelleneinbau_5F1.pvi","avi":"","play":true},
"de":{"text":"deutscher Text für Zelleneinbau_1_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelleneinbau_5F1.pvi","avi":"","play":true}},
"Zelle_2TO1_VS" : {"en":{"text":"english text for Zelle_2TO1_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelle_5F2TO1.pvi","avi":"","play":true},
"de":{"text":"deutscher text für Zelle_2TO1_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelle_5F2TO1.pvi","avi":"","play":true}},
"Zelle_3TO1_VS" : {"en":{"text":"english descripton for Zelle_3TO1_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelle_5F3TO1.pvi","avi":"","play":true},
"de":{"text":"deutsche Beschreibung für Zelle_3TO1_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelle_5F3TO1.pvi","avi":"","play":true}},
"Zelle_4TO1_VS" : {"en":{"text":"english descripton for Zelle_4TO1_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelle_5F4TO1.pvi","avi":"","play":true},
"de":{"text":"deutsche Beschreibung für Zelle_4TO1_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelle_5F4TO1.pvi","avi":"","play":true}},
"Zelleneinbau_2_VS" : {"en":{"text":"that is the Zelleneinbau_2_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelleneinbau_5F2.pvi","avi":"","play":true},
"de":{"text":"das ist Zelleneinbau_2_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelleneinbau_5F2.pvi","avi":"","play":true}},
"Zelle_3TO2_VS" : {"en":{"text":"attept to play the Zelle_3TO2_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelle_5F3TO2.pvi","avi":"","play":true},
"de":{"text":"versuchen wir Zelle_3TO2_VS abzuspielen","pvi":"app/resources/Uploaded/l-Creo 3D - Zelle_5F3TO2.pvi","avi":"","play":true}},
"Zelle_4TO2_VS" : {"en":{"text":"english text for Zelle_4TO2_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelle_5F4TO2.pvi","avi":"","play":true},
"de":{"text":"deutscher Text für Zelle_4TO2_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelle_5F4TO2.pvi","avi":"","play":true}},
"Zelleneinbau_3_VS" : {"en":{"text":"try to play here Zelleneinbau_3_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelleneinbau_5F3.pvi","avi":"","play":true},
"de":{"text":"Abspielen von Zelleneinbau_3_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelleneinbau_5F3.pvi","avi":"","play":true}},
"Zelle_4TO3_VS" : {"en":{"text":"here play Zelle_4TO3_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelle_5F4TO3.pvi","avi":"","play":true},
"de":{"text":"Abspielen von Zelle_4TO3_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelle_5F4TO3.pvi","avi":"","play":true}},
"Zelleneinbau_4_VS" : {"en":{"text":"try to play here Zelleneinbau_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Zelleneinbau_5F4.pvi","avi":"","play":true},
"de":{"text":"versuchen wir Zelleneinbau_4_VS abzuspielen","pvi":"app/resources/Uploaded/l-Creo 3D - Zelleneinbau_5F4.pvi","avi":"","play":true}},
"Deckelmontage_4_VS" : {"en":{"text":"here is the Deckelmontage_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Deckelmontage_5F4.pvi","avi":"","play":true},
"de":{"text":"hier zeigen wir Deckelmontage_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Deckelmontage_5F4.pvi","avi":"","play":true}},
"Deckel_drehen_4_VS" : {"en":{"text":"play here Deckel_drehen_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Deckel_5Fdrehen_5F4.pvi","avi":"","play":true},
"de":{"text":"abspielen von Deckel_drehen_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Deckel_5Fdrehen_5F4.pvi","avi":"","play":true}},
"Deckel_demontage_4_VS" : {"en":{"text":"play the sequence to Deckel_demontage_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Deckel_5Fdemontage_5F4.pvi","avi":"","play":true},
"de":{"text":"abspielen von Animation von Deckel_demontage_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Deckel_5Fdemontage_5F4.pvi","avi":"","play":true}},
"Schraubenmontage_4_VS" : {"en":{"text":"play here Schraubenmontage_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Schraubendemontage_5F4.pvi","avi":"","play":true},
"de":{"text":"zeige hier Schraubenmontage_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Schraubendemontage_5F4.pvi","avi":"","play":true}},
"Schraubendemontage_4_VS" : {"en":{"text":"the english text for Schraubendemontage_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Schraubenmontage_5F4.pvi","avi":"","play":true},
"de":{"text":"deutsche Beschreibung für Schraubendemontage_4_VS","pvi":"app/resources/Uploaded/l-Creo 3D - Schraubenmontage_5F4.pvi","avi":"","play":true}}
}
The advantage of such outsourcing file is that when you load it to memory via the $http.get() and set to global variable examle-> $scope.app.steuerDaten
Then you can access it simple e.g:
let param = "UE_FB_li_VS"
let lang="de"
let current_pvi=$scope.app.steuerDaten[param][lang].pvi
console.log("current_pvi=",current_pvi)
so accordign to the sample json above this will print in the console then
current_pvi=app/resources/Uploaded/l-Creo 3D - UE_5FFB_5Fli.pvi