I'm trying to render 2D text using Sprites in the Autodesk Forge viewer, but I can't get it to show up. If I consult the layer by console I see that it contains the created Sprite but nevertheless I can’t see it in the scene. I have tried different scaling and position settings but no results.
I attach the code below:
function createText(text, preferencia, tamanyo) {
var sprite = spriteTexto("Prueba texto sprite", preferencia, tamanyo);
if (!NOP_VIEWER.impl.overlayScenes['overlaySprites'])
NOP_VIEWER.impl.createOverlayScene('overlaySprites');
NOP_VIEWER.impl.addOverlay('overlaySprites', sprite);
}
function spriteTexto(text, preferencia, tamanyo) {
var fontface = NOP_VIEWER.fontName;
var fontsize = 18; //tamanyo
var borderThickness = 4;
var borderColor = { r:0, g:0, b:0, a:1.0 };
var backgroundColor = { r:0, g:0, b:0, a:0.0 };
var textColor = { r:0, g:0, b:255, a:1 }; //hexadecimalARgb(preferencia.color);
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.font = "Bold " + fontsize + "px " + fontface;
var metrics = context.measureText( text );
var textWidth = metrics.width;
context.fillStyle = "rgba(" + backgroundColor.r + "," + backgroundColor.g + "," + backgroundColor.b + "," + backgroundColor.a + ")";
context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + "," + borderColor.b + "," + borderColor.a + ")";
context.fillStyle = "rgba(" + textColor.r+", " + textColor.g + ", " + textColor.b + ", 1.0)";
context.fillText( text, borderThickness, fontsize + borderThickness);
var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: false } );
var sprite = new THREE.Sprite( spriteMaterial );
sprite.scale.set(1*fontsize,1*fontsize,1*fontsize);
sprite.position.set(5,5,6);
return sprite;
}
I would be very grateful if you could help me find the error, thank you very much in advance for your help!
EDIT:------------------------------------------------
We want to render 2D text that can be interacted with (specifically select, rotate, and move).
To do this currently we are working with meshes (using MeshBasicMaterial, Mesh and TextGeometry), but it turns out that the text does not look perfectly sharp, it presents aliasing and we’ve found that according to the API reference, the antialiasing is not applicable to 2d.
Here are some examples of the problem, as you can see, the more we move away from the plane, the worse the text looks (and even up close it doesn't look perfect):
We were trying to make a test representing the text with Sprites (despite the fact that it would mean having to change the entire implementation already made with meshes) to try to implement it in another way that will solve the problem. But we see that it is not possible either.
How can we correct the rendering of the text then? Is there a way to fix it or is this the most we can get in 2D? We've tried searching for information on this but we haven't find anything helpful.
Unfortunately, Forge Viewer doesn't support THREE.Sprite at present. It uses a self-maintained three.js r71 and removes this support as I know.
Could you share the use case in detail on why you want to use THREE.Sprite with Forge Viewer? If you don't want to share that publicly, you can send it to forge (DOT) help (AT) autodesk (DOT) com.
Related
For a chart like this
https://codepen.io/team/amcharts/pen/NmNLoL
function categoryAxisZoomed(ev) {
var axis = ev.target;
var start = axis.getPositionLabel(axis.start);
var end = axis.getPositionLabel(axis.end);
console.log("New range: " + start + " -- " + end);
}
How can I add a pre zoom to max level so that when a page loads, I see only one category.
I want to do this only for mobile.
Any help would be appreciated
Thanks
Use zoom to values like this
function zoomAxis(pass parameters) {
valueAxis.zoomToValues("start", "end");
}
For references: http://www.amcharts.com/docs/v4/tutorials/zooming-axis-via-api-or-external-scrollbar/
I have script that is taking a HTMLElement and the css.top and css.marginLeft of an element which refuses to set the properties in TypeScript.
here's my code:
let moveable1: HTMLElement = document.getElementsByClassName('moveable1')[0] as HTMLElement;
Here's how I'm getting the values and "trying" to set the properties.
console.log("**style.top** = " + (moveable1.style.top =
String((+this.chatScrollTop + +this.boxScrollTop).toFixed(0))));
console.log("**style.marginLeft** = " + (moveable1.style.marginLeft = String((+this.chatScrollLeft + +this.boxScrollLeft).toFixed(0))));
moveable1.style.top = String(moveable1.style.top);
moveable1.style.marginLeft = String(moveable1.style.marginLeft);
What's happening is:
moveable1.style.marginLeft and moveable1.style.top ALWAYS equals ""
I don't understand.
The console logs are reporting the correct values
style.top = 69
style.marginLeft = 100
top: **<<<=== "EMPTY"** and should be 69
marginLeft: **<<<=== "EMPTY"** and should be 100
Thoughts, anyone?
UPDATE:
Zeh suggested the solution:
I modified it a wee bit...
let top = +this.chatScrollTop + +this.boxScrollTop;
const marginLeft = this.chatScrollLeft + this.boxScrollLeft;
moveable1.style.top = top.toFixed(0) + "px";
moveable1.style.marginLeft = String(parseInt(marginLeft).toFixed(0)) + "px";
console.log("top: " + moveable1.style.top);
console.log("marginLeft: " + moveable1.style.marginLeft);
THANK YOU ZEH!
You're setting a style property to a number and then trying to re-read and convert it to a string. This doesn't work; top (et al) cannot be numbers therefore they're kept at their previous value("").
Also, you need units ("px", "pt", etc) when setting a style, otherwise it won't set either, even if it's a string. Hence when you try converting them from number to string you get another blank string.
// This returns 1
console.log(document.body.style.top = 1);
// Nevertheless, it didn't work, since this returns ""
console.log(document.body.style.top);
This is not a TypeScript problem, this is a JavaScript (rather, a DOM) "problem".
My suggestion is to simplify this code. It's not just hard to read, it's doing a lot that it shouldn't be doing - unnecessary conversions, depending on assignment side effects, etc.
Something like this should work:
const top = this.chatScrollTop + this.boxScrollTop;
const marginLeft = this.chatScrollLeft + this.boxScrollLeft;
moveable1.style.top = top.toFixed(0) + "px";
moveable1.style.marginLeft = marginLeft.toFixed(0) + "px";
I am currently working on a graphic design program for the iPad and have ran into a little problem using the textField with touch events.
I have to use the textField object to display text on the screen since it is the ONLY text object which I can disable anti-aliasing. (If you know of a way to do it with Spark, it would seriously change my life.)
The scope of my problem is the following:
I have a spark group which contains all the objects the end user adds to the screen (text, images).
Images added are spark:Image
Text added is flash.text.textField
I wrap the textField in a UIComponent then containingGroup.addElement(UIComponent)
Everything works really well until I get to movement.
I am using a view to hold the objects.
I created a spark label called touchPlatform, to which I have added my Begin, Move, End, and Touch_Out events to. I did this so I would not have to add an event listener to each object I add to the screen (performance hit). Below is the basic MXML setup:
<View>
<ContainerGroup/>
<TouchPlatform/>
</View>
Whenever I do something to the TouchPlatform, I mirror those changes to the selected object (Users have a list of objects which are on the screen they can select).
Down to the problem:
It seems the textFields are not reacting to the touch events correctly (not surprising since they are older components). When I drag my finger on the screen, everything works file until I hit a textField. When I enter or exit a text field, it throws a touch_out event.
Reasons why this should not happen:
I am touching the touchPlatform (its higher, it takes up the entire
screen)
Handlers are only on the touchPlatform, not on the textFields themselves
The fired event never tells me the e.target or e.currentTarget is anything other than the touchPlatform. I am doing specific tests asking for the exact object or if the object "is" a textField/label/image/other.
That is my major point of concern. If I could receive a touch_out event where I would receive a textField object as my target, I could simply ignore it. In this case, the return is as valid as possible; it says the event was triggered by the touchPlatform.
I have set the textField.selectable = false.
I have been noticing a problem which I think is a clue to this issue. When a GUI component is added to the screen (lets say a Spark:TextInput), unless I set the skinClass to a mobile version, it will still be selectable and editable even if it has been set enabled=false, its container has been disabled, groups and labels have overlayed it, etc. If you can see it, you can interact with it. The moment I set it to a mobile skin, everything starts working. I'm wondering if this flash component is disrupting the touch event in a similar way.
If anyone knows a solutions to this situation I would greatly appreciate it.
If someone has another simple solution to accomplishing this task, please let me know as well. I need to have this done on Monday, which is in 2.5 days.
Thank you in advance for the help
CODE:
Where Touch Platform gets created and how it is over Workbench Container (the thing that holds all the objects on the screen):
<s:Group height="600" width="100%" creationComplete="touchPlatform_creationCompleteHandler(event)">
<Components:WorkbenchContainer id="wrkBenchContainer">
</Components:WorkbenchContainer>
<s:VGroup>
<s:HGroup id="grpLoading" visible="{properties.loading}">
<s:BusyIndicator id="bsyLoading" symbolColor="#FFFFFF"/>
<s:Label id="lblLoading" text="Loading..." color="#FFFFFF"/>
</s:HGroup>
</s:VGroup>
<s:Label id="touchPlatform" width="100%" height="100%" creationComplete="touchPlatform_creationCompleteHandler(event)"/>
</s:Group>
EVENT HANDLER RESULT FOR TOUCH_OUT ATTACHED TO touchPlatform
public function handleTouchEnd(e:TouchEvent):void{
if(m_layersPanel.lstLayers.selectedIndex == -1)
return;
/*
var stopTouch:Boolean = false;
var reason:String = "";
if(e.stageX > (m_workbenchContainer.width + m_workbenchContainer.x) || e.stageX < 0 || e.stageY < 0 || e.stageY > (m_workbenchContainer.height + m_workbenchContainer.y)){
reason+= "OUT OF BOUNDS X:" + e.stageX + " Y:" + e.stageY + " WX:" + m_workbenchContainer.x + " WY:" + m_workbenchContainer.y + " MaxX:" + m_workbenchContainer.x + m_workbenchContainer.width + " MaxY:" + m_workbenchContainer.y + m_workbenchContainer.height;
stopTouch = true;
}
for(var z:int = 0; z < m_workbench.grpLayers.numElements; z++){
if(e.target == m_workbench.grpLayers.getElementAt(z)){
stopTouch = true;
reason += "TOUCHING OBJECT: " + e.target.toString();
}
}
*/
properties.bounds = "BOUNDS: ID: " + e.touchPointID + " X:" + e.stageX + " Y:" + e.stageY + " WX:" + m_workbenchContainer.x + " WY:" + m_workbenchContainer.y + " MaxX:" + m_workbenchContainer.x + m_workbenchContainer.width + " MaxY:" + m_workbenchContainer.y + m_workbenchContainer.height;
var stopTouch:Boolean = false;
if(e.currentTarget is Label){
reason += "Touched Label";
stopTouch = true;
}else if(e.currentTarget is TextField){
reason += "Touched TextField";
}else{
reason += "Unknown: " + e.currentTarget.toString();
}
if(!(e.currentTarget is Label))
{
properties.status = "TRIP OBJECT: " + e.touchPointID + "- " + reason;
//e.preventDefault();
//e.stopImmediatePropagation();
return;
}else if(e.stageX > (.95 * (m_workbenchContainer.width + m_workbenchContainer.x)) || e.stageX < 10 || e.stageY < 10 || e.stageY > (.95 * (m_workbenchContainer.height + m_workbenchContainer.y))){
properties.status = "OUTSIDE BOUNDS" + reason + e.currentTarget.toString();
}else{
properties.status = "VALID? " + reason + e.currentTarget.toString();
}
/* if(e.target is DoodleText || e.target is DoodleImage)
properties.status = "TOUCHED IMAGE OR TEXT";
else if(e.target is UIComponent){
properties.status = "Touched UI Component";
}else
properties.status = "Out Of Bounds";
else
properties.status = "END TOUCH";
*/
//Primary finger removed
if(primTouchID == e.touchPointID){
primTouchID = -1;
secTouchID = -1;
properties.primaryStatus = "RESET";
properties.secondaryStatus = "RESET";
var obj:DoodleInterface = DoodleInterface(m_layersPanel.lstLayers.selectedItem);
m_undoHandler.addUndo(m_layersPanel.lstLayers.selectedItem,"TRANSFORM",(originalX + "," + originalY + "," + originalWidth + "," + originalHeight), (obj.getActualX() + "," + obj.getActualY() + "," + obj.getActualWidth() + "," + obj.getActualHeight()));
}
//Secondary finger removed
if(secTouchID == e.touchPointID){
secTouchID = -1;
properties.secondaryStatus = "RESET";
}
//Stop Stretching if both primary and secondary fingers have been removed
if(primTouchID == -1 && secTouchID == -1){
stretching = false;
//Ensure Object is Snapped to Grid
var endobj:DoodleInterface = DoodleInterface(m_layersPanel.lstLayers.selectedItem)
endobj.setX(int(endobj.getActualX()));
endobj.setY(int(endobj.getActualY()));
endobj.setWidth(int(endobj.getActualWidth()));
endobj.setHeight(int(endobj.getActualHeight()));
}
m_workbench.refreshSelection();
}
I found the solution. For anyone encountering the same issue, please note that older flash components don't exactly like to play nice with spark components.
As you can see in my above code, I was using a spark label as my touch area. The textFields within the group below the touch area were pushing through the spark label and causing the touch_out event to fire.
I have resolved this by having everyone play by the same rules. Instead of mixing a spark label and a flash textField, I have created changed the touch area from a Spark Label to a Text Field.
I create the textfield in actionscript, set its x,y,width,height, and selectable=false. Then add the textField to a UIComponent, and then add the UIComponent to the same group as before.
From what I can tell, everything is working well.
Below is my code. If anyone has any questions, please let me know.
Touch Platform Creation:
if(grpContainer.containsElement(touchPlatformContainer))
grpContainer.removeElement(touchPlatformContainer);
touchPlatform = new TextField();
touchPlatform.selectable = false;
touchPlatform.width = 1152;
touchPlatform.height = 600;
touchPlatform.x = 0;
touchPlatform.y - 0;
touchPlatformContainer = new UIComponent;
touchPlatformContainer.addChild(touchPlatform);
grpContainer.addElement(touchPlatformContainer);
Same Assignments of Touch Events as before:
touchPlatform.removeEventListener(TouchEvent.TOUCH_BEGIN, m_controlPanel.handleTouchBegin);
touchPlatform.removeEventListener(TouchEvent.TOUCH_MOVE, m_controlPanel.handleTouchMove);
touchPlatform.removeEventListener(TouchEvent.TOUCH_END, m_controlPanel.handleTouchEnd);
touchPlatform.removeEventListener(TouchEvent.TOUCH_OUT, m_controlPanel.handleTouchEnd);
touchPlatform.addEventListener(TouchEvent.TOUCH_BEGIN, m_controlPanel.handleTouchBegin);
touchPlatform.addEventListener(TouchEvent.TOUCH_MOVE, m_controlPanel.handleTouchMove);
touchPlatform.addEventListener(TouchEvent.TOUCH_END, m_controlPanel.handleTouchEnd);
touchPlatform.addEventListener(TouchEvent.TOUCH_OUT, m_controlPanel.handleTouchEnd);
I am working on an application that will allow a user to scale an image. The issue that I am having with the method below is that the scaling is always taking place on the previous scale point.
For example: If I scale the image up one and then scale the image down one. I have to scale down twice to get it back to the point I want it to be.
Any help with this is greatly appreciated.
Here is my current code:
private var sourceBMD:BitmapData = testImage.source as BitmapData
private var matrixScaleX:Number = 1;
private var matrixScaleY:Number = 1;
private var baseScaleX:Number = .05;
private var baseScaleY:Number = .05;
private function sourceZoom(zoomType:Boolean = false):void{
var matrix:Matrix = new Matrix();
var matriximage:BitmapData;
if(zoomType){
matrixScaleX = matrixScaleX + baseScaleX;
matrixScaleY = matrixScaleY + baseScaleY;
matrix.a = matrixScaleX;
matrix.d = matrixScaleY
}else{
matrixScaleX = matrixScaleX - baseScaleX;
matrixScaleY = matrixScaleY - baseScaleY;
matrix.a = matrixScaleX;
matrix.d = matrixScaleY;
}
matriximage = new BitmapData(sourceBMD.width, sourceBMD.height, false, 0x0000000);
trace('MatrixScaleX: ' + matrixScaleX);
trace('MatrixScaleY: ' + matrixScaleY);
trace('BaseScaleX: ' + baseScaleX);
trace('BaseScaleY: ' + baseScaleY);
trace('Matrix: ' + ObjectUtil.toString(matrix));
matriximage.draw(sourceBMD, matrix);
testImage.source = matriximage;
}
That looks fine, I'd suspect that the problem lies with your input or the place this is getting called.
In order for it to work, events need to happen like this in your code:
capture input -> scale image -> draw image.
Since you appear to be setting the image to draw at the end of this function, I would check that this function is being called after the input has finished processing.
Can you confirm that's what's happening?
I'm trying to set the width of a Textfield() object based on it's string content that I have set-
Is there a way to dynamically set this once the string has been sent to the object?
I have:
var t1:TextField = new TextField()
t1.x = stage.stageWidth / 2;
t1.y = stage.stageHeight / 2;
t1.text = "some string that i would want to render";
t1.textColor = 0x000000;
t1.cacheAsBitmap = true;
addChild(t1);
Thanks for any suggestions...
jml
TextField.autoSize?
edit:
You should read the documentation correctly, it's a member variable that actually needs to be set. I'll give you a quick example on how this works:
var tf:TextField = new TextField();
tf.text = 'Some text.';
tf.autoSize = TextFieldAutoSize.LEFT;
tf.x = ( stage.stageWidth - tf.width ) / 2;
tf.y = ( stage.stageHeight - tf.height ) / 2;
Alternatively you can also align the text field first and use TextFieldAutoSize.CENTER to keep it aligned in the center.
t1.text = "Some text";
t1.width = t1.textWidth + 5;
t1.height = t1.textHeight + 5;
Why the + 5? Because Adobe sucks and adds an internal gutter around your stuff. Per the docs this is supposed to be 2px per side, but it's actually slightly more, so you add another +1 for good measure.
you could try using the getCharBoundaries() method (it returns a rectangle surrounding a character at a specified index). Use that to get the rectangle from the first and last chars and set the width to the difference of those rectangles.
Pretty convoluted, there's got to be a better way, but if not this should work.