I have an item renderer for a grid that has a fairly basic updateDisplayList function:
override protected function updateDisplayList( w : Number, h : Number ) : void
{
super.updateDisplayList( w, h );
var labelWidth : Number = Math.min( _labelDisplay.measuredWidth, w );
var labelHeight : Number = Math.min( _labelDisplay.measuredHeight, h );
_labelDisplay.setActualSize( labelWidth, labelHeight );
var labelX : Number = ( w - _labelDisplay.width ) / 2;
var labelY : Number = ( h - _labelDisplay.height ) / 2;
_labelDisplay.move( labelX, labelY );
//this is just for debugging
graphics.clear();
graphics.beginFill( 0xFF0000, 0.5 );
graphics.drawRect( labelX, labelY, labelWidth, labelHeight );
graphics.endFill();
}
where _labelDisplay is a spark label. When I scroll the grid (this is a cuatom grid, not mx:Grid or AndvancedDataGrid) when new rows appear at the bottom of the grid updateDisplayList is called and the code to re-draw the background and move / resize the label executes.
The problem is that these chanegs are not reflected in the view. The text is mis-aligned as a label that used to display a large string now displays a short string so the measuredWidth has changed.
The next time I scroll the renders update to look like they should - but updateDisplayList is NOT called here (on the renderes). All that happens is that the renderers are re-positioned in the grid.
Both the background and the label are displayed incorrectly initially so it's not just the label mis-behaving.
Anyone got any idea why this is happening?
Thanks
Just a guess, but does this make any difference?
override protected function updateDisplayList( w : Number, h : Number ) : void
{
var labelWidth : Number = Math.min( _labelDisplay.measuredWidth, w );
var labelHeight : Number = Math.min( _labelDisplay.measuredHeight, h );
_labelDisplay.setActualSize( labelWidth, labelHeight );
var labelX : Number = ( w - _labelDisplay.width ) / 2;
var labelY : Number = ( h - _labelDisplay.height ) / 2;
_labelDisplay.move( labelX, labelY );
super.updateDisplayList( w, h ); // Call updateDisplayList after moving / resizing _labelDisplay
}
Related
I'm learning QtCharts.
I need to zoom a chart, and adjust the range of the axis-Y accordingly, in order to make the logical visible part of the line can be completely plotted in the real visible area of the ChartView.
For example:
auto chart = new QtCharts::QChart;
auto lines = new QtCharts::QLineSeries;
QDateTime dt = QDateTime::currentDateTime();
for( int i = 0; i < 100; ++i ) {
lines->append( dt.toMSecsSinceEpoch(), std::pow( i, 2 ) );
dt = dt.addMSecs( 500 );
}
chart->addSeries( lines );
auto axisX = new QtCharts::QDateTimeAxis( chart );
axisX->setTickCount( 13 );
axisX->setFormat( "ss.zzz" );
chart->addAxis( axisX, Qt::AlignBottom );
lines->attachAxis( axisX );
auto axisY = new QtCharts::QValueAxis( chart );
axisY->setLabelFormat( "%i" );
chart->addAxis( axisY, Qt::AlignLeft );
lines->attachAxis( axisY );
auto cv = new QtCharts::QChartView( chart );
setCentralWidget( cv );
resize( 800, 600 );
cv->show();
At beginning, my chart looks like this:
When zooming in, I call "zoomin" method of chart:
chart->zoomIn();
But the line would "goes out of the visible area of the View", like this:
I want it look like this:
So, I called the scroll method of chart:
chart->scroll( 0, -50 );
But it obviously cannot be applied within my product program,
As:
I don't wana "repaint" multi-times, as I belive that the chart would
be repaint after any calls to axisY->setRange and chart->zoom, and
chart->scroll, and so on...
How should I finger out the arguments of the axisY->setRange to
adjust it? I looked through the members of
QLineSeries/QChart/QValue/QChartView, but I didn't found a way to calculate the new max/min value of the axis-Y.
I belive that there must be a method can resolve my problem, but I don't know.
Thanks! Sorry for my poor English.
Instead of rotating the camera with camera.rotation or with the lookAt() function
I'd like to pass a look vector directly to the camera... Is it possible to set a camera look vector directly and is it possible to read the look vector from the camera?
The camera does not have a "look vector", so you cannot set it.
You can, however, construct a point to look at by adding your look vector to the camera's position, and then calling
camera.lookAt( point );
Here is how to determine the direction in which the camera is looking, assuming the camera either has no parent (other than the scene).
The camera is looking down its internal negative z-axis, so create a vector pointing down the negative z-axis:
var vector = new THREE.Vector3( 0, 0, - 1 );
Now, apply the same rotation to the vector that is applied to the camera:
vector.applyQuaternion( camera.quaternion );
The resulting vector will be pointing in the direction that the camera is looking.
Alternatively, you can use the following method, which works even if the camera is a child of another object:
camera.getWorldDirection( dirVector );
three.js r.73
These other answers are very insightful, but not completely correct. The code returns a vector that points in the same direction that the camera is pointing at. That's a great start!
But unless the camera is at the origin (0, 0, 0) (or lies exactly on the line segment that connects the origin to the rotated vector point without passing beyond that point so that the point is behind the camera) the camera won't be looking at that point. Clearly -- just common sense -- the position of the camera also influences what points are being looked at. Just think about it!!
The camera method lookAt() looks at a point in 3D space regardless of where the camera is. So to get a point that the camera is looking at you need to adjust for the camera position by calling:
vec.add( camera.position );
It is also worth mentioning that the camera is looking not at a single point but is looking down a line of an infinite number of points, each at a different distance from the camera. The code from the other answers returns a vector that is exactly one unit in length because the application of a quaternion to the normalized z-axis vector (0, 0, -1) returns another normalized vector (in a different direction). To calculate the look at point at an arbitrary distance x from the camera use:
THREE.Vector3( 0, 0, -x ).applyQuaternion( camera.quaternion ).add( camera.position );
This takes a point along the z-axis at a distance x from the origin, rotates it to the direction of the camera and then creates a "world point" by adding the camera's position. We want a "world point" (and not just a "relative to the camera point") since camera.lookAt() also takes a "world point" as a parameter.
The above answer wrapped as a util, this is what I do with my Three Utils:
THREE.Utils = {
cameraLookDir: function(camera) {
var vector = new THREE.Vector3(0, 0, -1);
vector.applyEuler(camera.rotation, camera.eulerOrder);
return vector;
}
};
Call it with THREE.Utils.cameraLookDir(camera);
What I did was to use method lookAt(Vector) just before render the scene like in below code , just try it using it on a new html file :)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style >
*{
margin: 0 ;
}
#WebGlElement {
height: 500px;
width: 500px;
background-color: red
}
</style>
</head>
<body>
<script src="js/three.min.js"></script>
<div id="WebGlElement"></div>
<script>
var contianer = document.getElementById("WebGlElement");
var origin = new THREE.Vector3(0,0,0);
// CREATE THREE BASIC ELEMENTS
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 40, 300/300, 1, 1000 );
var renderer = new THREE.WebGLRenderer();
// SET RENDERER AND ATTACH IT TO BODY
renderer.setSize( 500, 500 );
//document.body.appendChild( renderer.domElement );
contianer.appendChild( renderer.domElement);
// CREATE A GEOMETRY AND ADD IT TO SCENE
/*var geometry = new THREE.BoxGeometry( 1, 1, 5 );
var material = new THREE.MeshBasicMaterial( { color: 0x1abc9c } );
material.wireframe = true ;
material.wireframeLinewidth = 0.1 ;
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );*/
var geometry = new THREE.Geometry();
geometry.elementsNeedUpdate=true;
geometry.vertices.push(
new THREE.Vector3( -0, 1, 0 ),
new THREE.Vector3( -1, -1, 0 ),
new THREE.Vector3( 1, -1, 0 )
);
geometry.faces.push(
new THREE.Face3( 0, 1, 2 ),
new THREE.Face3( 2, 1, 0 )
);
var material = new THREE.MeshBasicMaterial( { color: 0x1abc9c } );
//material.wireframe = true ;
//material.wireframeLinewidth = 0.1 ;
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
var axisHelper = new THREE.AxisHelper( 1 );
scene.add( axisHelper );
// POSITION OF CAMER ON Z
camera.position.z = 5;
camera.position.y = 5;
camera.up = new THREE.Vector3(0,0,1);
var dir = 1;
var number = 0.115
// CREATE FUNCTION FOR RENDER
var render = function () {
requestAnimationFrame( render );
//circle.rotation.x += 0.01;
if ( camera.position.x> 5) {
dir = -1;
}
if ( camera.position.x< -5) {
dir = 1;
}
camera.lookAt(cube.position);
//camera.rotation.y += 0.015 * dir;
camera.position.x += number * dir;
renderer.render(scene, camera);
};
// EXECUTE FIRST RENDER
render();
</script>
</body>
</html>
in this code created a animation sprite using spritesheet. the sprite created body. there boy can move on world using button.
//spritesheet plist
[[CCSpriteFrameCache sharedSpriteFrameCache]
addSpriteFramesWithFile:#"boyRunning.plist"];
// Create a sprite sheet with the boyRunning images
spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"boyRunning.png"];
[self addChild:spriteSheet];
// Load up the frames of our animation
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = 2; i <=7; ++i) {
[walkAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"boyRunning%d.png", i]]];
}
walkAnim = [CCAnimation animationWithFrames:walkAnimFrames delay:0.1f];
// Create a sprite for our boy
CGSize winSize = [CCDirector sharedDirector].winSize;
self.boy = [CCSprite spriteWithSpriteFrameName:#"boyRunning1.png"];
_boy.position = ccp(100, 90);
self.walkAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:walkAnim restoreOriginalFrame:NO]];
[_boy runAction:_walkAction];
[spriteSheet addChild:_boy];
// boy body creation
b2BodyDef boyBodyDef;
boyBodyDef.type = b2_dynamicBody;
boyBodyDef.linearDamping = 1;
boyBodyDef.angularDamping = 1;
boyBodyDef.position.Set(230.0f/PTM_RATIO,(FLOOR_HEIGHT+91.0f)/PTM_RATIO);
boyBodyDef.userData = _boy;
boyBody = world->CreateBody(&boyBodyDef);
b2Body* dynamicBody = world->CreateBody(&boyBodyDef);
// Define another box shape for our dynamic body.
b2PolygonShape boxshape;
boxshape.SetAsBox(11.0f/PTM_RATIO, 30.0f/PTM_RATIO);//These are mid points for our 1m box
// Define the dynamic body fixture.
b2FixtureDef fixtureDef;
fixtureDef.shape = &boxshape;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
armFixture = boyBody->CreateFixture(&fixtureDef);
dynamicBody->SetTransform( b2Vec2( 10, 20 ), 1 );
When the button is pressed
For movement use
body->ApplyForce( b2Vec2(0,50), bodiy]->GetWorldCenter() );
For jump
body[0]->ApplyLinearImpulse( b2Vec2(50,50), body->GetWorldCenter() );
Where body is your body attached to sprite and b2ve2(x,y) is the direction .
There is any way to make a text "textured" - with a result similar to this: http://www.entheosweb.com/fireworks/patterned_text.asp
In Flex (so using AS3)?
I though it was a simple issue, but I'm stuck: i'm googling it from days and was not able to find aa way or workaround to do it...
The rough idea is this:
Create a TextField with whatever font you need, and write whatever text you want in there.
Create a new BitmapData object and draw() the TextField so that you get a bitmap representation of it.
Get your texture as a BitmapData object (if you load in a jpg, it'll be in the Bitmap that you get after it's loaded)
Create a new BitmapData object and use copyPixels() to draw your texture, while using the first BitmapData object (the blitted TextField) as an alpha mask: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#copyPixels()
Voila, textured text.
Let me know if you need some code, but it should be pretty straightforward
Edit with code:
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
public class TestTexturedText extends Sprite
{
private var m_text:TextField = null; // the TextField that we use to write our text
private var m_texture:BitmapData = null; // the texture that we're going to texture our TextField with
private var m_textBMD:BitmapData = null; // the BitmapData that we use to draw our TextField
private var m_drawPoint:Point = new Point; // Point used in drawing the final BitmapData
private var m_drawRect:Rectangle = new Rectangle;// the Rectangle we use to determine which part of the texture to take
// the texture we're using
[Embed(source="texture.jpg")]
private var m_textureImage:Class;
public function TestTexturedText()
{
this._createText( "Trebuchet Ms", 50.0 ); // create our textfield
this._getTexture(); // get our texture
// create textured text 1
var bmd:BitmapData = this.getTexturedText( "hello world" );
var b:Bitmap = new Bitmap( bmd );
b.x = 250.0;
b.y = 50.0;
this.addChild( b );
// create textured text 2
bmd = this.getTexturedText( "testing" );
b = new Bitmap( bmd );
b.x = 250.0;
b.y = 100.0;
this.addChild( b );
}
/**
* Get a BitmapData of the text we want, textured
* #param text The text we're looking at
* #param randomPos Should we take a random position from our text, or just start at (0,0)?
* #return A BitmapData object containing our textured text
*/
public function getTexturedText( text:String, randomPos:Boolean = true ):BitmapData
{
// set the text
this.m_text.text = text;
var tw:int = int( this.m_text.width + 0.5 ); // quick conver to int without clipping
var th:int = int( this.m_text.height + 0.5 );
// reuse our previous BitmapData if we can, rather than always creating a new one
if ( this.m_textBMD == null || this.m_textBMD.width < tw || this.m_textBMD.height < th )
this.m_textBMD = new BitmapData( tw, th, true, 0x00000000 );
else
this.m_textBMD.fillRect( this.m_textBMD.rect, 0x00000000 ); // clear the bitmapdata of the old rendering
// draw our text
this.m_textBMD.draw( this.m_text, null, null, null, null, true );
// set our draw rect position
this.m_drawRect.x = ( randomPos ) ? Math.random() * ( this.m_texture.width - tw ) : 0.0;
this.m_drawRect.y = ( randomPos ) ? Math.random() * ( this.m_texture.height - tw ) : 0.0;
this.m_drawRect.width = tw;
this.m_drawRect.height = th;
// get a new bitmap data (that we'll return) and copy our pixels, using the first bmd as an alpha mask
var ret:BitmapData = new BitmapData( tw, th, true, 0x00000000 );
ret.copyPixels( this.m_texture, this.m_drawRect, this.m_drawPoint, this.m_textBMD, this.m_drawPoint );
return ret;
}
// creates the TextField that we'll use to write our text
private function _createText( font:String, size:Number ):void
{
var tf:TextFormat = new TextFormat( font, size );
this.m_text = new TextField;
this.m_text.defaultTextFormat = tf;
this.m_text.autoSize = TextFieldAutoSize.LEFT;
// debug add it to the stage
this.m_text.x = 250.0;
this.addChild( this.m_text );
}
// gets the texture that we'll use to create our text
private function _getTexture():void
{
this.m_texture = ( ( new this.m_textureImage ) as Bitmap ).bitmapData;
// debug add it to the stage
var debug:Bitmap = new Bitmap( this.m_texture );
debug.scaleX = debug.scaleY = 0.2;
this.addChild( debug );
}
}
}
Some points:
It'll take a minor bit of work to turn it into a class - this is a main class (as in I use it to run the application)
Edit the m_textureImage embed to point to the texture you want to use, or alternatively, load one in.
Just call the function getTexturedText() to get a BitmapData with the text that you want
You can remove where I add the different items (texture, textfield, result) to the stage. That's just to show you what's going on
This is pure AS3, but it'll also work in flex
It's been a while since I used ActionScript, but I could give some ideas.
Simplest solution I can think of is that you can load an image in a sprite and then mask it using another sprite which has embedded text.
Other option, more difficult, is to render text as shapes by manually defining each letter as points. Then you could use Papervision3D to texture these shapes. I have not used Papervision3D before but as any other game engine allows texturing this should be possible.
As others have answered, using the text as a mask for an image is how this can be achieved in Flash or Flex.
The answer by divillysausages is a good one, but since you comment there that you are confused by the absence of Flex markup in that example, here is a minimal example in MXML markup:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application creationComplete="img.mask=txt" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Canvas>
<mx:Text id="txt" cacheAsBitmap="true" fontSize="48" fontWeight="bold" text="LOREM IPSUM" />
<mx:Image id="img" cacheAsBitmap="true" autoLoad="true" source="http://farm3.static.flickr.com/2783/4092743591_3fb90fa599.jpg" />
</mx:Canvas>
</mx:Application>
The principle is the same as in the other answers, the text has to be a bitmap to be used as a mask for the image (here achieved by cacheAsBitmap="true").
I have write a simple example that adds a canvas and draw a rectangle with stroke size 20 scale mode none.
The problem is that if I call getBounds() first time I will get a correct result but after I call scale(); the getBounds() function will give me a wrong result.
It will take in cosideration the stroke but stroke has scalemode to none and on the screen nothing happens but in the result I will have a x value smaller. Can sombody tell me how can I fix this?
protected var display :Canvas;
protected function addCanvas():void
{
display = new Canvas();
display.x = display.y = 50;
display.width = 100;
display.height = 100;
display.graphics.clear();
display.graphics.lineStyle( 20, 0x000000, 0.5, true, LineScaleMode.NONE );
display.graphics.beginFill( 0xff0000, 1 );
display.graphics.drawRect(0, 0, 100, 100);
display.graphics.endFill();
area.addChild( display );
traceBounce();
}
protected function scale():void
{
var m :Matrix = display.transform.matrix;
var apply :Matrix = new Matrix();
apply.scale( 2, 1 );
apply.concat( m );
display.transform.matrix = apply;
traceBounce();
}
protected function traceBounce():void
{
trace( display.getBounds( this ) );
}
Setting the width/height and scaling the same display object can give confusing results. Does your Canvas class do anything unusual (e.g. set the scrollRect or add a mask)?
Also you could try getting bounds of the Canvas' parent instead, or setting cacheAsBitmap on the Canvas and seeing if that helps?