Community Tip - Learn all about the Community Ranking System, a fun gamification element of the PTC Community. X
I would like to be able to wrap text for a 3DLabel. My use case is if I can take a data field within a work instruction program to be able to be linked to a 3DLabel. This way it will show the most up to date work instructions that could could range from a couple sentences to a couple of paragraphs. Right now if I use a 3DLabel, it will take that text and keep it in the same line.
The workaround that I am using is putting the text into a 3D image so that way it is showing in the size and format fit best for the experience. But this does not allow that text to be configurable to latest instructions.
Thank you,
Brian
Hello,
Sadly, this is limitation in behavior of 3D Label Widget.
Please see this article :
https://www.ptc.com/en/support/article/CS307920
I can give you another workaround :
https://www.ptc.com/en/support/article/CS320480
https://www.ptc.com/en/support/article/CS321955
As updated can take some times, I would recommand to do update of 3D SVG when opening the View or with a progress bar displayed during some seconds when clicking a button, for example.
Best regards,
Samuel
Hi @BAR3887 ,
so far I know , there is no functionality to do this directly with 3Dlabel widget because they do not understand any formatting characters e.g. new line etc. and 3Dlabel widget could not contain more lines text.
Possible options could be split the text to many 3DLabel as different text blocks, which are aligned in rows and columns where different properties are applied e.g. / size /css style etc.
Another option to use a 3dImage widget instead. You can use a svg file format / also this could be generated by code dynamically and allows to use multiline text. Pease, see the post “Display SVG as 3D Image on Hololens”
Here is also a general info to the SVG format
Thanks for the help.
Based on your comments (and others), here's my attempt at dynamically creating an SVG for text. It works in "Preview" and on the HoloLens2.
First, I added a "3D Image" to my Canvas named "3DImage-1". I set the source to a random SVG file that I found.
Next I added the following functions to Home.js:
// This function accepts an image widget name (imgWidget, ex: '3DImage-1')
// and some text/HTML (imgText) to render as an SVG image on the widget.
// There are optional arguments for basic features like background color,
// font color, font size, etc.
$scope.renderSVG = function(imgWidget, imgText, bgColor='#414141', fontColor='#FCFCFC', fontSize='xx-large') {
// Simple 600x400 SVG image template with a foreignobject section to embed HTML (text).
let svgData = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
id="svg1"
crossorigin="anonymous"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
width="600" height="400" >
<foreignObject x="0" y="0" width="600" height="400">
<xhtml:div
id='svgcontainer'
style="margin:5px;padding:5px;height:380px;display:flex;justify-content:center;align-content:center;flex-direction:column;font-family:Tahoma,sans-serif;font-size:${fontSize};text-align:center;background-color:${bgColor};color:${fontColor};">
<xhtml:p
id='svgtext'>
${imgText}
</xhtml:p>
</xhtml:div>
</foreignObject>
</svg>`;
// Base64 encode the SVG template defined above and create the SVG URL
let svgURL = "data:image/svg+xml;base64," + btoa(svgData);
// Set the image widget to the SVG URL
$scope.view.wdg[imgWidget].src=svgURL;
}
// Verify the renderSVG function works by setting a 3DImage widget to text.
$scope.sampleSVG = function() {
// Name of image widget to edit
let sampleImgWidget = '3DImage-1';
// Text to render on 3DImage widget
let sampleText = 'Here is some <xhtml:b>TEXT</xhtml:b> that we can render inside an SVG and it should be centered and word-wrapped if everything worked out ok';
// Render sample
$scope.renderSVG(imgWidget=sampleImgWidget, imgText=sampleText);
}
// After the document has loaded, change the image to the sample SVG
angular.element(document).ready($scope.sampleSVG);
Preview Output
Hi @JG_9770075 I'm using your code but I don't get the expected result.
My widget is called 3DImage-1 and the rest is exactly the same but I get nothing.
Of course I see it's trying to do something because It doesn't show the sampe svg.
Any clue? Do you need to see anything from my project?
Thanks
BR
Hi @AndreaT ,
I think the code is working fine but there is an issue in the format of the community editor.
the problem is that the editor always change this code - therefore I will add it as picture there:
I think the example from @JG_9770075 is working fine and was added with the correct code but unfortunately the editor corrected it so that it was not working in this context . The picture on the bottom is the correct syntax
Another curiosity.
Instead of hardcoding text in the JS window, is it possible to add text from an external file/s uploaded to the resources folder? What would be the best solution? In my case I'm also thinking about a resource that can be easily translated.
Like a menu in two langs and when I select the EN lang it picks up the text from resFile_en.??? and if I choose japanese it'd look for resFile_jp.???
This is more complex but it's also closer to my use case.
Thanks!
I think you would just need to write a JS function that accepts a filename parameter (such as resFile_en.html or resFile_jp.html) and returns the contents. If you were using the function I wrote above, you could pass the text to the renderSVG function:
someText = readTextFile('res_en.hmtl');
$scope.renderSVG(imgWidget=sampleImgWidget, imgText=someText);
I have not tested this but maybe something similar to:
readTextFile = function(filename) {
var txt;
fetch('app/resources/Uploaded/' + filename)
.then(function(response) {
response.text().then(function(text) {
txt = text;
done();
});
});
return txt;
}
Also, note that if you use HTML tags, they all need to have the <xhtml:tag> prefix in the tag name or the html won't render.
// SHOULD WORK TO BOLD THE TEXT:
<xhtml:b>Bold Text</xhtml:b>
// WONT WORK:
<b>Bold Text</b>
Hi @JG_9770075 and @AndreaT ,
I think the idea how to call file from e.g. upload folder is good but it will not work because the asynchronous call will not wait until data is received an at least as the code example is shown it will not work.
So what we can do is
$scope.$on('$ionicView.afterEnter',function(){
//event when view is loaded
doMyFetch();
$timeout(()=>{myFunction()},2000); // called after 2 secs delay
//because there is sure that it is loaded
}
of course this works but when we want to used the loaded data directly we need to call this in the then branch of the fetch event - so I think is for me the better solution.$scope.renderSVGxhtml = function(imgWidget, imgText, bgColor , fontColor, fontSize='xx-large') {
// Simple 600x400 SVG image template with a foreignobject section to embed HTML (text).
let svgData = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
id="svg1"
crossorigin="anonymous"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
width="600" height="500" >
<foreignObject x="0" y="0" width="600" height="500">
<xhtml:div
id='svgcontainer'
style="margin:5px;padding:5px;height:480px;display:flex;justify-content:center;align-content:center;flex-direction:column;font-family:Tahoma,sans-serif;font-size:${fontSize};text-align:center;background-color:${bgColor};color:${fontColor};">
${imgText}
</xhtml:div>
</foreignObject>
</svg>`;
let svgURL = "data:image/svg+xml;base64," + btoa(svgData);
$scope.setWidgetProp(imgWidget,'src',svgURL)
}
//=========================================================================
$scope.readTextFile =function(filename, functionCall) {
fetch('app/resources/Uploaded/' + filename).then((response) => response.text())
.then((text) => {
let evalTxt=functionCall.replace("my_sample_text_here",text)
eval(evalTxt)
});
}
//=========================================================================
//=========================================================================
// Verify the renderSVG function works by setting a 3DImage widget to text.
$scope.sampleSVG3 = function() {
// Name of image widget to edit
let sampleImgWidget = '3DImage-3';
let bgColor= '#DE3163' //'#414141' according https://htmlcolorcodes.com/
let frontColor= '#40E0D0' //'#FCFCFC'
let myFunctionCall ='$scope.renderSVGxhtml("'+sampleImgWidget+'", "my_sample_text_here","'+bgColor+'", "'+frontColor+'","xx-large");'
$scope.readTextFile('testText1.txt', myFunctionCall)
}
//===========================================================================
// Verify the renderSVG function works by setting a 3DImage widget to text.
//===========================================================================
$scope.sampleSVG4 = function() {
// Name of image widget to edit
let sampleImgWidget = '3DImage-4';
// Render sample
let bgColor= '#FF7F50' //'#414141' according https://htmlcolorcodes.com/
let frontColor= '#DFFF00' //'#FCFCFC'
let myFunctionCall ='$scope.renderSVGxhtml("'+sampleImgWidget+'", "my_sample_text_here","'+bgColor+'", "'+frontColor+'","xx-large");'
$scope.readTextFile('testText2.txt', myFunctionCall)
}
//========================================================================
//========================================================================
$scope.$on('$ionicView.afterEnter',function(){$timeout(()=>{$scope.sampleSVG3();$scope.sampleSVG4();},0)})
//======================================================================================================
e.g. the one text file is something like this <testText2.txt> in the upload folder:
<xhtml:small>Here is another (samll)<xhtml:hr/></xhtml:small><xhtml:b>(bold)Ii Still use The XHTML Syntax <xhtml:hr/></xhtml:b> <xhtml:br/>in an SVG as <xhtml:b>fofeignObject svgcontainer</xhtml:b><xhtml:br/> <xhtml:i> (italic)which is working OK! <xhtml:hr/></xhtml:i><xhtml:b>File testText2.txt <xhtml:hr/></xhtml:b>
and here the result in preview
I attached the demo project here.
please, pay attention that editor changed the code and if a copy and paste is used it needs correction
or you can take the code from the example project