flex 实用公式

 

实用公式 

    统领全书,我们已经有了各种运动和效果的公式。我已经提取出了最实用和最常用的公式、方程、以及代码的摘录,并将它们列在本章的最后。我认为将它们放到同一个地方应该对大家非常有帮助,因此我将这些我认为最需要的内容放到一起作为整体的一个参考资料。我将会在这一页夹上书签。 

 

 

第三章 
基础三角函数的计算: 
角的正弦值 = 对边 / 斜边 
角的余弦值 = 邻边 / 斜边 
角的正切值 = 对边 / 邻边 

 

弧度转换为角度以及角度转换为弧度: 
弧度 = 角度 * Math.PI / 180 
角度 = 弧度 * 180 / Math.PI 

 

向鼠标(或者任何一个点)旋转: 
// 用要旋转到的 x, y 坐标替换 mouseX, mouseY 
dx = mouseX - sprite.x; 
dy = mouseY - sprite.y; 
sprite.rotation = Math.atan2(dy, dx) * 180 / Math.PI; 

 

创建波形: 
// 将 x, y 或其它属性赋值给 Sprite 影片或影片剪辑, 
// 作为绘图坐标,等等。 
public function onEnterFrame(event:Event){ 
value = center + Math.sin(angle) * range; 
angle += speed; 

 

创建圆形: 
// 将 x, y 或其它属性赋值给 Sprite 影片或影片剪辑, 
// 作为绘图坐标,等等。 
public function onEnterFrame(event:Event){ 
xposition = centerX + Math.cos(angle) * radius; 
yposition = centerY + Math.sin(angle) * radius; 
angle += speed; 

 

创建椭圆: 
// 将 x, y 或其它属性赋值给 Sprite 影片或影片剪辑, 
// 作为绘图坐标,等等。 
public function onEnterFrame(event:Event){ 
xposition = centerX + Math.cos(angle) * radiusX; 
yposition = centerY + Math.sin(angle) * radiusY; 
angle += speed; 

 

获得两点间的距离: 
// x1, y1 和 x2, y2 是两个点 
// 也可以是 Sprite / MovieClip 坐标,鼠标坐标,等等。 
dx = x2 – x1; 
dy = y2 – y1; 
dist = Math.sqrt(dx*dx + dy*dy); 

 

第四章 

十六进制转换为十进制: 
trace(hexValue); 

 

十进制转换为十六进制: 
trace(decimalValue.toString(16)); 

 

颜色组合: 
color24 = red << 16 | green << 8 | blue; 
color32 = alpha << 24 | red << 16 | green << 8 | blue; 

 

颜色提取: 
red = color24 >> 16; 
green = color24 >> 8 & 0xFF; 
blue = color24 & 0xFF; 
alpha = color32 >> 24; 
red = color32 >> 16 & 0xFF; 
green = color32 >> 8 & 0xFF; 
blue = color232 & 0xFF; 

 

穿过某点绘制曲线: 
// xt, yt 是我们想要穿过的一点 
// x0, y0 以及 x2, y2 是曲线的两端 
x1 = xt * 2 – (x0 + x2) / 2; 
y1 = yt * 2 – (y0 + y2) / 2; 
moveTo(x0, y0); 
curveTo(x1, y1, x2, y2); 

 

第五章 
角速度转换为 x, y 速度: 
vx = speed * Math.cos(angle); 
vy = speed * Math.sin(angle); 

 

角加速度(作用于物体上的 force)转换为 x, y 加速度: 
ax = force * Math.cos(angle); 
ay = force * Math.sin(angle); 

 

将加速度加入速度: 
vx += ax; 
vy += ay; 

 

将速度加入坐标: 
movieclip._x += vx; 
sprite.y += vy; 

 

第六章 
移除出界对象: 
if(sprite.x - sprite.width / 2 > right || 
sprite.x + sprite.width / 2 < left || 
sprite.y – sprite.height / 2 > bottom || 
sprite.y + sprite.height / 2 < top) 

// 删除影片的代码 

 

重置出界对象: 
if(sprite.x - sprite.width / 2 > right || 
sprite.x + sprite.width / 2 < left || 
sprite.y – sprite.height / 2 > bottom || 
sprite.y + sprite.height / 2 < top) 

// 重置影片的位置和速度 

 

屏幕环绕出界对象: 
if(sprite.x - sprite.width / 2 > right) 

sprite.x = left - sprite.width / 2; 

else if(sprite.x + sprite.width / 2 < left) 

sprite.x = right + sprite.width / 2; 

if(sprite.y – sprite.height / 2 > bottom) 

sprite.y = top – sprite.height / 2; 

else if(sprite.y + sprite.height / 2 < top) 

sprite.y = bottom + sprite.height / 2; 

 

摩擦力应用(正确方法): 
speed = Math.sqrt(vx * vx + vy * vy); 
angle = Math.atan2(vy, vx); 
if(speed > friction) 

speed -= friction; 

else 

speed = 0; 

vx = Math.cos(angle) * speed; 
vy = Math.sin(angle) * speed; 

 

摩擦力应用(简便方法): 
vx *= friction; 
vy *= friction; 

 

第八章: 
简单缓动运动,长形: 
var dx:Number = targetX - sprite.x; 
var dy:Number = targetY - sprite.y; 
vx = dx * easing; 
vy = dy * easing; 
sprite.x += vx; 
sprite.y += vy; 

 

简单缓动运动,中形: 
vx = (targetX - sprite.x) * easing; 
vy = (targetY - sprite.y) * easing; 
sprite.x += vx; 
sprite.y += vy; 

 

简单缓动运动,短形: 
sprite.x += (targetX - sprite.x) * easing; 
sprite.y += (targetY - sprite.y) * easing; 

 

简单弹性运动,长形: 
var ax:Number = (targetX - sprite.x) * spring; 
var ay:Number = (targetY - sprite.y) * spring; 
vx += ax; 
vy += ay; 
vx *= friction; 
vy *= friction; 
sprite.x += vx; 
sprite.y += vy; 

 

简单弹性运动,中形: 
vx += (targetX - sprite.x) * spring; 
vy += (targetY - sprite.y) * spring; 
vx *= friction; 
vy *= friction; 
sprite.x += vx; 
sprite.y += vy; 

 

简单弹性运动,短形: 
vx += (targetX - sprite.x) * spring; 
vy += (targetY - sprite.y) * spring; 
sprite.x += (vx *= friction); 
sprite.y += (vy *= friction); 

 

偏移弹性运动: 
var dx:Number = sprite.x - fixedX; 
var dy:Number = sprite.y - fixedY; 
var angle:Number = Math.atan2(dy, dx); 
var targetX:Number = fixedX + Math.cos(angle) * springLength; 
var targetY:Number = fixedX + Math.sin(angle) * springLength; 
// 如前例弹性运动到 targetX, targetY 

 

第九章 
距离碰撞检测: 
// 从影片 spriteA 和 spriteB 开始 
// 如果使用一个空白影片,或影片没有半径(radius)属性 
// 可以用宽度或高度除以 2。 
var dx:Number = spriteB.x - spriteA.x; 
var dy:Number = spriteB.y - spriteA.y; 
var dist:Number = Math.sqrt(dx * dx + dy * dy); 
if(dist < spriteA.radius + spriteB.radius) 

// 处理碰撞 

 

多物体碰撞检测: 
var numObjects:uint = 10; 
for(var i:uint = 0; i < numObjects - 1; i++) 

// 使用变量 i 提取引用 
var objectA = objects[i]; 
for(var j:uint = i+1; j 

  // // 使用变量 j 提取引用 
  var objectB = objects[j]; 
  // perform collision detection 
  // between objectA and objectB 

 

第十章 
坐标旋转: 
x1 = Math.cos(angle) * x - Math.sin(angle) * y; 
y1 = Math.cos(angle) * y + Math.sin(angle) * x; 

 

反坐标旋转: 
x1 = Math.cos(angle) * x + Math.sin(angle) * ;y 
y1 = Math.cos(angle) * y - Math.sin(angle) * x; 

 

第十一章 
动量守恒的数学表达式: 
                (m0 – m1) * v0 + 2 * m1 * v1 
v0Final = ---------------------------------------------- 
                          m0 + m1 

                (m1 – m0) * v1 + 2 * m0 * v0 
v1Final = --------------------------------------------- 
                          m0 + m1 


动量守恒的 ActionScript 表达式,短形: 
var vxTotal:Number = vx0 - vx1; 
vx0 = ((ball0.mass - ball1.mass) * vx0 + 
2 * ball1.mass * vx1) / 
(ball0.mass + ball1.mass); 
vx1 = vxTotal + vx0; 

 

第十二章 
引力的一般公式: 
force = G * m1 * m2 / distance2 

 

ActionScript 实现万有引力: 
function gravitate(partA:Ball, partB:Ball):void 

var dx:Number = partB.x - partA.x; 
var dy:Number = partB.y - partA.y; 
var distSQ:Number = dx * dx + dy * dy; 
var dist:Number = Math.sqrt(distSQ); 
var force:Number = partA.mass * partB.mass / distSQ; 
var ax:Number = force * dx / dist; 
var ay:Number = force * dy / dist; 
partA.vx += ax / partA.mass; 
partA.vy += ay / partA.mass; 
partB.vx -= ax / partB.mass; 
partB.vy -= ay / partB.mass; 

 

第十四章 
余弦定理 
a2 = b2 + c2 - 2 * b * c * cos A 
b2 = a2 + c2 - 2 * a * c * cos B 
c2 = a2 + b2 - 2 * a * b * cos C 

 

ActionScript 的余弦定理: 
A = Math.acos((b * b + c * c - a * a) / (2 * b * c)); 
B = Math.acos((a * a + c * c - b * b) / (2 * a * c)); 
C = Math.acos((a * a + b * b - c * c) / (2 * a * b)); 

 

第十五章 
基本透视法: 
scale = fl / (fl + zpos); 
sprite.scaleX = sprite.scaleY = scale; 
sprite.alpha = scale; // 可选 
sprite.x = vanishingPointX + xpos * scale; 
sprite.y = vanishingPointY + ypos * scale; 

 

Z 排序: 
// 假设有一个带有 zpos 属性的 3D 物体的数组 
objectArray.sortOn("zpos", Array.DESCENDING | Array.NUMERIC); 
for(var i:uint = 0; i < numObjects; i++) 

setChildIndex(objectArray[i], i); 

 

坐标旋转: 
x1 = cos(angleZ) * xpos - sin(angleZ) * ypos; 
y1 = cos(angleZ) * ypos + sin(angleZ) * xpos; 
x1 = cos(angleY) * xpos - sin(angleY) * zpos; 
z1 = cos(angleY) * zpos + sin(angleY) * xpos; 
y1 = cos(angleX) * ypos - sin(angleX) * zpos; 
z1 = cos(angleX) * zpos + sin(angleX) * ypos; 

 

3D 距离: 
dist = Math.sqrt(dx * dx + dy * dy + dz * dz); '

 

 

ref:http://www.cnblogs.com/liongis/archive/2010/08/10/1796558.html

“离散数学”教学的探讨与思考

 

“离散数学”教学的探讨与思考

文章编号:1672-5913(2009)10-0127-03 
摘要:“离散数学”是计算机及相关专业的一门重要课程。该课程概念多、理论性强、高度抽象。在教学过程中,教师要强调课程的实用价值和重要性,引起学生足够的重视,在教学中注重反例的作用,做到一题多解,举一反三,注重特殊与一般相结合及时归纳与小结,提升教学质量。 
关键词:离散数学;举一反三;启发式教学 
中图分类号:G642 
文献标识码:B 
 
1引言 
离散数学”是计算机科学与技术专业的重要专业基础课程,在计算机科学中有着广泛的应用。它不仅是许多计算机专业课,如“数据结构”、“操作系统”、“编译原理”、“数据库原理”、“人工智能”、“数字逻辑”等的必备基础,也对培养学生抽象思维能力和逻辑推理能力起着重要作用。该课程由计算机科学与工程实践中所需要的数学理论和方法所组成,概念多、理论性强、高度抽象。学生在学习该课程时,往往看不到离散数学的知识在计算机科学中的具体应用,因而不仅不重视离散数学的学习,还怕学这门课程。因此如何提高离散数学课程的教学水平和质量,对学生后续课程的学习和毕业以后的科学研究和实践有重要意义。在离散数学的教学实践过程中,笔者积累了一些实际效果较好的做法,现提出供大家商榷。 
2强调实用价值和重要性,引起学生足够重视 
近年来,计算机学科的发展与离散数学的主要内容如数理逻辑、集合论和图论等都有非常紧密的联系。数理逻辑是研究推理的学科,在人工智能、数据库理论等的研究中有着重要的应用;图论和集合论为数据结构和数据表示理论奠定了数学基础,也为许多问题从算法角度加以解决提供了抽象和描述的重要方法。因此,在实际教学过程中,教师更应注重让学生了解离散数学在现实应用中的主要作用,有意识地引导学生运用所学理论分析和解决实际问题,从而让学生充分感受到这门课程的魅力和实用价值。例如在讲授平面图时,可以给出它们在印刷电路板、集成电路等方面的应用。 
数理逻辑部分在计算机的硬件设计中应用非常突出,我们可以利用命题中各个联结词运算规律,把由高低电平表示的各信号之间的转换与二进制之间的运算连接起来,用数学方法解决电路设计的问题,使得整个设计过程更加系统化。很多学生在解决这样的问题时已经使用了离散数学知识,但并没有意识到自己使用了离散数学中的数理逻辑。针对这样的问题,教师在讲授课程过程中,一定要将每部分离散数学知识是怎样应用到计算机科学中说清楚,让学生充分认识到离散数学的重要性。 
再如,在介绍图论中根树时,可将根树中求最优树的方法运用到计算机通讯中,以使信息在传输过程中既准确无误又节省二进制位。在讲解数理逻辑部分时,可以将真值表部分的内容运用到逻辑电路的设计上,在此基础上进一步启发学生运用这部分知识设计简单的表决器、抢答器等。这样不仅激发了学生学习离散数学的积极性,还进一步加强了学生理论联系实际的能力。 
3一题多解,举一反三 
离散数学具有多样性的特点,同一个概念可以给出不同的描述方法,例如,讲解二元关系的性质时给出如下定义: 
设R为定义在集合A上的二元关系。 
① 若 x(x A→

ref:www.kjlww.com/news_show.php

Integrating Flex into Ajax applications

Building Ajax applications has proven to be a consistent method for providing engaging applications. However, the explosion in popularity of Adobe Flex cannot be ignored. As we are continually pushed to create the best user experience, we're often faced with the difficult task of integrating Flash-based assets embedded in our Ajax applications. This article discusses the integration of Flash content with existing Ajax content using the FABridge, a code library developed by Adobe to handle this very task.

To be an Ajax developer today is pretty special. We're always at the front lines, ready to greet users and offer the best first impression to the applications we build for them. As Web standards advance and more vendors decide to implement them, our jobs have become easier, allowing us to focus on the user experience. The further advancements in JavaScript frameworks such as Ext JS, jQuery, and Prototype have also allowed us to spend less time worrying about whether our code will work across the platforms we're asked to support, leaving more time to innovate.

Although there are certainly more tools, techniques, and resources available to us today, there is also a shift in development methodology that serves as a push toward the rich world of Flash development. For many shops, the development workflow would involve the user interface (UI) group to produce designs that support a server-side-generated application. With just the JavaScript frameworks we have now, we're pushed in the direction of application development for the client side. However, the emergence of the Flex platform — a free, open source framework for producing Flash applications — brings us further into the application development arena. This type of innovation is good for us on the client side, but we must ensure that we handle the process of integrating it with current architectures in a thoughtful and careful manner.

Before I introduce code samples showing how to work with Ajax and Flex assets, you need to understand the tools and skills required:

  • I produced the Ajax samples in this article using the Ext JS JavaScript library, so you need to download the .zip file that contains the library and supporting documentation.
  • Next, grab a copy of the free Adobe Flex 3 SDK and Adobe Flash Player 9 with debugging capability, if you don't already have it.
  • Although not required to follow along in this article, you may also want to check out at least a trial version of Adobe Flex Builder 3, an Eclipse-based IDE that enables rapid Flex application development in addition to superior debugging and profiling capabilities (see Resources).
  • Finally, a working knowledge of PHP is helpful.

The integration issue

If you were looking forward to replacing all your Ajax content with Flex assets, your task would be much simpler. However, this is an unlikely and often unreasonable approach, because there are many reasons to preserve traditional Ajax functionality. Fortunately, there's no reason you can't keep the best of both environments to produce a rich, cohesive application.

There are quite a few simplistic methods for passing data to ActionScript code from the Flash container (HTML/JavaScript code), including the use of query strings and <param> tags. However, this method is limited to passing data into the container. A more powerful technique is to use the ExternalInterface class, an application program interface (API) used to broker communication between the ActionScript and JavaScript languages. The use of ExternalInterface is best demonstrated by the example in Listing 1:


Listing 1. ExternalInterface example
// ActionScript code
function exposed():String
{
   return "Hello, JavaScript!";
}

ExternalInterface.addCallback( "getActionScript", exposed );

// HTML/JavaScript code
<script language="JavaScript">

var result = flashObject.getActionScript();

</script>

<object id="flashObject" ...>
   <embed name="flashObject" ... />
</object>

Listing 1 demonstrates a stripped-down example of how to use the ExternalInterface class to register an ActionScript function so that JavaScript code can call it. You do this by first defining an ActionScript function, then using the addCallback() method to expose the function to JavaScript for execution. On the HTML side, simply obtain a handle to the Flash container and call the function, which was named using the first parameter to the addCallback() method. Although this demonstration concentrated on exposing functions to the JavaScript code, you can just as easily go the other way by using the call() method of the ExternalInterface class.

The ExternalInterface class can be quite powerful, but there are significant drawbacks to implementing it. To use ExternalInterface, you must be able to write code to implement both the ActionScript and JavaScript environments. This not only requires added skill but double the effort. In this situation, maintaining code as well as two very robust skill sets can become a challenge.

To address the limitations of development against the Flash external API, Adobe has released the FABridge. The FABridge, which ships with the Flex SDK, is a small library used to expose Flash content to scripting in the browser and works in most major browser platforms. With the FABridge, plumbing code that was required to directly implement the Flash external API is now virtually eliminated. Further, the skills required to implement the bridge aren't as robust. As a JavaScript developer, you simply need to be able to understand what's available to you in the way of ActionScript properties and methods. Let's get started with a few examples that demonstrate the capabilities of the FABridge.

An FABridge tutorial

Before you get started using the FABridge, here are the materials and development environment you'll be working with. After downloading the latest Flex SDK, configure the directory structure shown in Listing 2:


Listing 2. Directory structure for the FABridge tutorial
/
+--- bridge
|      +--- fabridge.js
|      +--- fabridge.as
|      
+--- index.html

The directory structure is straightforward: You just have an index page and the FABridge scripts hooked into their own directory named bridge. The location of the FABridge library files depends on your environment. Because I'm using Flex Builder 3 Professional on Mac OS X, my library files reside in install_root/sdks/frameworks/3.0.0/javascript/fabridge/.

Now that you have the appropriate architecture in place, you can begin creating the skeletons on both the HTML/JavaScript and ActionScript sides. Use the code from Listing 3 to develop the HTML/JavaScript skeleton:


Listing 3. HTML/JavaScript skeleton
<html>
<head>
<title>FABridge Tutorial</title>

<script type="text/javascript" src="bridge/FABridge.js"></script>
<script type="text/javascript">
   // ... 
</script>

</head>
<body>
</body>
</html>

As you can see, you simply hook the FABridge JavaScript library to your code, and all the functionality of the bridge is immediately available. Next, use the code from Listing 4 to implement the bridge on the ActionScript side:


Listing 4. Application skeleton
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
       xmlns:bridge="bridge.*"
       layout="absolute"
       width="300"
       height="142">
	   
   <bridge:FABridge bridgeName="flex" /> 
   <mx:TextInput x="70" y="54" id="txt_test" text="FABridge rocks!"/>
   
</mx:Application>

This code might be a bit more unfamiliar to you. The UI is kept clean and simple by defining a single text input control with the ID txt_test and a default value of FABridge rocks! The bridge namespace is defined, and all classes in the bridge directory are imported. Finally, the Flex application is given a name for the bridge to use to access it: flex. To compile this Flex code into a working SWF document, use the mxmlc utility from the Flex 3 SDK. The most basic compile command is shown in Listing 5:


Listing 5. Compiling MXML
path_to_flex_bin_folder/mxmlc path_to_mxml file

The command in Listing 5 compiles the source file and outputs an SWF file with the same file name as the MXML in the same directory. Assuming a successful compilation, you can now hook the resulting SWF into your HTML file, as shown in Listing 6:


Listing 6. Linking the resulting SWF file
<embed src=�main.swf� />

Note: The code in Listing 6 is deliberately light to keep focus on the task of demonstrating the FABridge. Unless you're targeting a specific environment (Listing 6 is targeting Mozilla), you'll want to add more intelligence in the way of object tags and other load scripts.

Assuming that all went well, your application should now look similar to Figure 1:


Figure 1. The sample application
Sample application

Now that you have successfully compiled and linked the Flex application into the HTML container, invoke your first FABridge functions to obtain a reference to the Flex application. Use the code in Listing 7 to fill in the empty <script> tag in your HTML skeleton file:


Listing 7. Obtaining a reference to the Flex application
// global variable, holds reference to the Flex application
var flexApp;  
  
var initCallback = function() {  
   flexApp = FABridge.flex.root();  
   return;  
}  
// register the callback to load reference to the Flex app
FABridge.addInitializationCallback( "flex", initCallback ); 

The code in Listing 7 starts by defining a global JavaScript variable that will hold a reference to the Flex application when the FABridge obtains it. A callback function is defined that sets the global variable and is invoked through the addInitializationCallback() FABridge method. Using this code is simply a matter of matching the name of the bridge that you configured in the Flex application. From here, you're able to access all sorts of ActionScript functionality from the JavaScript code.

Working with ActionScript objects

Now that you've obtained a global reference to the Flex application, you can access ActionScript objects through the consistent interface that the FABridge provides. In the ActionScript world, you would typically access objects through dot notation object.id. Rather than expose ActionScript objects in dot notation, however, the FABridge makes these objects available through function calls. It is a little different at first, but all you need to know is the template to follow. An object traditionally identified in ActionScript as object.id would now be accessed as object.getId(). This is best demonstrated through example: Type the code from Listing 8 into your HTML skeleton to try it out:


Listing 8. Getting ActionScript objects by ID
// get the text input control 
var txt = flexApp.getTxt_test();

The variable txt is an object that represents the text input control with the ID txt_test from the Flex application. You can see the template you would need to follow for gaining access to other ActionScript objects by ID. The declaration begins with the global reference to the Flex application, then a method call that always begins with the string get followed by the ID of the target object. Notice that the name of the ID must begin with a capital letter in this declaration.

Getting and setting the properties of ActionScript objects is similar to the process just used. Keeping up with our example of manipulating the text input control, use the code from Listing 9 to get and set the text property:


Listing 9. Get and set ActionScript properties
alert( "old: " + txt.getText() );
	
txt.setText( "Reset!" );
	
alert( "new: " + txt.getText() );

The code in Listing 9 first alerts the original value of the text input control from the Flex application. By following the template described earlier, you can see that the text property is obtained through a function call, with the get string prepended and the property name camel cased. The set() method uses the same process but accepts a parameter used to configure the new value of the object. After the code in Listing 9 executes, you should see a screen similar to Figure 2:


Figure 2. Setting ActionScript object properties
Setting ActionScript object properties

Now, let's move on to the easiest manipulation of all: calling ActionScript object methods. This process requires no special considerations on your part. ActionScript object methods are used in JavaScript code just as they would be used in ActionScript code. The code in Listing 10 demonstrates the invocation of a method on your text input control:


Listing 10. Invoking ActionScript methods
txt.setVisible( false );

The code in Listing 10 sets the text input control in the Flex application to be invisible. The object can still be referenced and manipulated, it's just not physically visible. Between the ActionScript and JavaScript worlds, this is no change in the way the methods are invoked.

One of the more powerful features of the FABridge is the ability to pass functions between JavaScript and ActionScript code. Check out the code in Listing 11, which dynamically copies the value of the text input in Flex to a <div> on the HTML/JavaScript side:


Listing 11. Passing functions
// define a function used as a callback to JavaScript
var txtCallback = function( event ) {  
   // get the object which fired the event
   var swf_source = event.getTarget();  
   
   document.getElementById( "copy" ).innerHTML = swf_source.getText();
	  
   return;  
}  
txt.addEventListener( "change", txtCallback );

The code in Listing 11 is a JavaScript callback function that's fired each time the text input control value from the Flex application changes. When the value changes, it is copied to a <div> tag with the ID copy. This type of functionality can be very powerful, especially when attempting any sort of integration work between Ajax and Flex content. With both environments relying heavily on events, it's key to be able to have them work together.

The last feature this article explores is exception handling. By default, when you use try . . . catch blocks throughout your JavaScript code, you'll be able to at least access an error code that you can then look up in the online reference for ActionScript errors. This methodology certainly works, but during development, you want access to as much information up front as possible. While using the FABridge, you can get this information simply by installing Flash Player 9 with debugging. With this feature installed, you have access to line numbers, file names, error types, and stack traces. Use the code in Listing 12 to see an example:


Listing 12. Exception handling
try {
   alert( flexApp.throwsAnError() );
}
catch( e ) {
   var msg = "";
   for( var i in e ) {
      msg += i + " = " + e[i];
   }
   alert( msg );
}

An error is thrown from the code in Listing 12 because the method throwsAnError() does not exist. The code from the catch block outputs an alert that looks similar to Figure 3:


Figure 3. Exception data
Exception data

As you can see, this data is far more useful than a single error code and less work to troubleshoot. When you're working with complex integration issues between differing technologies such as JavaScript and ActionScript, you'll appreciate this extra help.


Putting it all together

So far, this article has taken a tutorial-type approach to showing the capabilities of the FABridge. Now it's time to use a real-world scenario to demonstrate its usefulness. As indicated earlier, you want to integrate and use the best of both the Ajax and Flex worlds. One of the components that really shines on the Flex side is its charting capability. Although it's not a free library, it is worth the added cost if you're looking to do some intense client-side application programming. The example you'll work with here is a combination of a PHP service that serves dummy data containing the number of messages received in certain categories for specific users. The data from the PHP service is loaded into a grid control using the Ext JS JavaScript framework, then the same data is pushed over the FABridge as a data provider to a pie chart in Flex. Start by taking at look at the PHP service in Listing 13:


Listing 13. The PHP service
<?php
   $users = array();
   array_push( $users, "Paul" );
   array_push( $users, "Nancy" );
   array_push( $users, "Ned" );
   array_push( $users, "Lucy" );

   $email = array();
   $email[ "email" ] = array();
   $email[ "totalCount" ] = count( $users );
	
   for( $i = 0; $i < count( $users ); $i++ ) {
      $tmp = array();
      $tmp[ "user" ] = $users[$i];
      $tmp[ "friends" ] = rand( 0, 100 );
      $tmp[ "family" ] = rand( 0, 100 );
      $tmp[ "spam" ] = rand( 0, 100 );
      array_push( $email[ "email" ], $tmp );
   }
	
   echo json_encode( $email );
?>

Note: The data in this service is hard coded and only meant to demonstrate the concept.

Next, take a look at Listing 14, which is the MXML to generate the pie chart:


Listing 14. Flex pie chart
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                xmlns:bridge="bridge.*"
                width="600"
                height="800">
   <bridge:FABridge bridgeName="flex" />
   <mx:Script>
   <![CDATA[    

      [Bindable]
      public var email:Object;
    
      private function displaySpam( data:Object,
                                    field:String,
                                    index:Number,
                                    percentValue:Number ):String {
         var temp:String= (" " + percentValue).substr(0,6);
         return data.user + ": " + '\n' + "Total Spam: " + data.spam + '\n' + temp + "%";
      }
   ]]>
   </mx:Script>


   <mx:Panel title="Spam E-mail">
      <mx:PieChart id="chart" 
                   height="100%" 
                   width="100%"
                   paddingRight="5" 
                   paddingLeft="5" 
                   showDataTips="true" 
                   dataProvider="{email}">          
         <mx:series>
            <mx:PieSeries nameField="user"
                          labelPosition="callout" 
                          field="spam" 
                          labelFunction="displaySpam">
            </mx:PieSeries>
         </mx:series>
      </mx:PieChart>  
      <mx:Legend dataProvider="{chart}"/>
   </mx:Panel>
</mx:Application>

This code was taken from the Adobe documentation and modified to fit the scenario as well as configured for use with the FABridge. One thing to note here is that the variable named email is bindable, which means that any references to this data set will be updated automatically. This works great, because you'll be sending data over the bridge to this same variable, which is then used as the data provider to the pie chart.

The last piece to this puzzle is the JavaScript code in Listing 15:


Listing 15. Produce the grid, populate the chart
<link rel="Stylesheet"
         type="text/css"
         href="../global/ext-2.0.2/resources/css/ext-all.css" />

<script type="text/javascript" src="bridge/FABridge.js"></script>
<script type="text/javascript" src="../global/ext-2.0.2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../global/ext-2.0.2/ext-all-debug.js"></script>
<script type="text/javascript">

Ext.onReady( function() {
   // global variable, holds reference to the Flex application
   var flexApp;  
	  
   var initCallback = function() {  
      flexApp = FABridge.flex.root(); 
		
      // load the data store, grid, populate the pie chart from JavaScript
      initUI();
		 
      return;  
   }  

   // register the callback to load reference to the Flex app
   FABridge.addInitializationCallback( "flex", initCallback );
	
   function initUI() {
	
      // create a data store using the PHP service
      var ds_email = new Ext.data.JsonStore(
         {
            url: "service.php",
            root: "email",
            fields: [ "user", "family", "friends", "spam" ]
         }
      );
		
      // when the data store loads, update the pie chart
      ds_email.load( 
         {
            callback: function( r, o, s ) {
               // send an array of objects over the bridge to fill in the pie chart
               var arr_email = new Array();
					
               for( var i = 0; i < r.length; i++ ) {
                  var tmp = new Object();
                  tmp.user = r[i].data.user;
                  tmp.family = r[i].data.family;
                  tmp.friends = r[i].data.friends;
                  tmp.spam = r[i].data.spam;
						
                  arr_email.push( tmp );
               }
					
               flexApp.setEmail( arr_email );	
            }
         }
      );
		
      // create a populate the grid.
      var grid_email = new Ext.grid.GridPanel(
         {
            title: "E-mail Count",
            store: ds_email,
            columns: [
               { header: "User", dataIndex: "user" },
               { header: "Family", dataIndex: "family" },
               { header: "Friends", dataIndex: "friends" },
               { header: "Spam", dataIndex: "spam" }
             ],
             height: 300,
             width: 450,
             renderTo: "grid-email"
         }
      );	
   }
} );

</script>

The first thing to notice about this code are the links to the Ext JS resources needed to make it work. After hooking in the default styles and debug scripts for Ext, an onReady block is configured. This block is executed only after a full Document Object Model (DOM) is ready. You should be familiar with the code used to populate the global flexApp variable with a reference to the Flex application. One addition to the callback is the execution of the initUI function. This function is used to create an Ext data store using the PHP service and to populate an Ext grid control using the resulting data in the store. When the Ext data store is loaded, a data structure is created and pushed over the FABridge so that the data binds as a data provider to the pie chart. The final product is shown in Figure 4:


Figure 4. The final product
Final product

As you scan the data in the grid, it should match up with what's represented in the pie chart. This really is a powerful concept, and you can see the possibilities it has to offer.

Although this was a single real-world example of how you might want to implement the FABridge, there are several other popular ways to use this library. Syncing security information for remote service authentication and techniques to consistently brand and personalize applications are just a couple of examples of how best to use the bridge.


Conclusion

Adobe Flex is an incredible technology that is just starting to reveal its true potential. However, no single product will solve all the wants and needs of developers and users, so it's important that we keep our minds open and explore the possibilities of integration using the FABridge.


Resources

Learn

Get products and technologies

  • Adobe Flex: Visit the Flex product page.
     
  • Ext JS: Download the Ext JS JavaScript framework.
     

Discuss

About the author

Brice Mason

Brice Mason is a husband and father from Albany, New York. He is also a developer, writer, and speaker who frequently starts sentences with "Wouldn't it be cool if . . . ." When not spending time with his family, he can be found writing code and writing about code.

ref:www.ibm.com/developerworks/web/library/wa-aj-flex/#ibm-pcon

flex, component's life-cycle

这篇文章帮了我很大的忙,转了

Earlier today I fixed a minor code issue. It took seconds to identify, but I remember being a little stumped by a similar problem in my early Flex days. The difference now is that I'm familiar with the component life-cycle.

You may think it is only worth reading up on the Flex component life-cycle if you intend to create advanced components, but that's not true, even when you are doing nothing other than extending basic mxml components a little knowledge goes a long way.

To demonstrate the problem take a look at the init method for this simple mxml component called TimeInputBar (which extends Canvas).

 

   
      //<code>Init</code> is called when the component's <code>initialize</code> event is fired:
   
      public var time:Number;
   
       
   
      public function init():void
   
      {
   
          time = 0;
   
      }

That's simple enough. Now take a look at the ActionScript which is creating an instance of the TimeInputBar:

 

   
      var t:TimeInputBar = new TimeInputBar();
   
      t.time = 12;
   
      addChild(t);

Again, simple code, but did you spot the problem? With a little bit of knowledge it's easy to see that time will always be reset to 0 and will never be 12. Why?

When you create a component using the new operator, only part of the life-cycle completes. The component gets as far as the configuration stage, which means you can set properties on the component (to be processed by the component later) but the life-cycle will not go any further than that. It is in effect, paused.

However, all the really cool stuff in the life-cycle, like creating the component's child elements, measuring the component, drawing the component and dispatching events happens during the next stage.

It is only when you add the component to the display list using addChild or addChildAt that the life-cycle continues (in other words ... it continues when the component has a parent).

As mentioned, the next phase is the one in which the cool stuff happens: In more detail, this means that the preinitialize event is dispatched, the component's children are created, the initialize event is dispatched and the component's validation methods are called (those are beyond the scope of this article) and if that's not enough for you, when all that is done then everybody's favourite event, creationComplete is dispatched.

So, with that knowledge in hand let's revisit the order of execution for the original example:

  • Create component using 'new' operator
  • Set time variable to 12
  • Add component to display list
  • initialize event is fired
  • init() method is called
  • time variable is set to 0

Many beginners make the assumption that the preinitialize and initialize events are dispatched early on - don't beat yourself up, that's a reasonable assumption to make. However those events may actually be dispatched after you've set initial values for some of your component's properties.

So, what's the solution? We could simply swap the order of our code:

 

   
      //no worky!
   
      t.time = 12;
   
      addChild(t);
   
       
   
      //worky
   
      addChild(t);
   
      t.time = 12;


...but I'm hoping you can see the issue; components should be just a little more flexible than that!

A perfectly acceptable solution here would be to perform a simple check inside our init method:

 

   
      public var time:Number;
   
       
   
      private function init():void
   
      {
   
          if(isNaN(time)) time = 0;
   
      }


[Edit - it's also perfectly acceptable to set 'time' to 0 when you first declare it - this post is not really concerned with which solution you choose, but rather it uses simplified code to explain why such a problem may arise in the first place.]

Once that is done, it will not matter if you set time before or after you add your component to the display list. If the value is set externally before init is called, the value will not be overridden.

You can read a little more about the Flex component life-cycle in one of my earlier posts here.

ref:nwebb.co.uk/blog/

 

 

the data:url protocol

所谓"data"类型的Url格式,是在RFC2397中 提出的,目的对于一些“小”的数据,可以在网页中直接嵌入,而不是从外部文件载入。例如对于img这个Tag,哪怕这个图片非常非常的小,小到只有一个 点,也是要从另外一个外部的图片文件例如gif文件中读入的,如果浏览器实现了data类型的Url格式,这个文件就可以直接从页面文件内部读入了。

data类型的Url格式早在1998年就提出了,时至今日,Firfox、Opera、Safari和Konqueror这些浏览器都已经支持,但是IE直到7.0版本都还没有支持,IE不支持的东西太多了,也不差这一个。:(

小例子

下面这个html代码可以在支持data类型Url的浏览器中运行,例如Firefox。运行后会看到一条蓝色渐变底色的标题。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<style type="text/css">
.title {
  background-image:url(data:image/gif;base64,R0lGODlhAQAcALMAAMXh96HR97XZ98Hf98Xg97DX97nb98Lf97vc98Tg973d96rU97ba97%2Fe96XS9wAAACH5BAAAAAAALAAAAAABABwAAAQVMLhVBDNItXESAURyDI2CGIxQLE4EADs%3D);
  background-repeat:repeat-x;
  height:28px;
  line-height: 28px;
  text-align:center;
}
</style>
</head>
<body>
<div class="title">Hello, world!</div>
</body>
</html>

这个渐变的蓝色底色实际上是用一个1x28的小图片通过横行重复(repeat-x)形成的。这个图片很小,不过104个字节,直接嵌入到html或css文件还是很合适的。

data格式的Url最直接的好处是,这些Url原本会引起一个新的网络访问,因为那里是一个网页的地址,现在不会有新的网络访问了,因为现在这里是网页的内容。这样做,会减少服务器的负载,当然同时也增加了当前网页的大小。所以对“小”数据特别有好处。

data类型Url的形式

既然是Url,当然也可以直接在浏览器的地址栏中输入。

data:text/html,<html><body><p><b>Hello, world!</b></p></body></html>

在浏览器中输入以上的Url,会得到一个加粗的"Hello, world!"。也就是说,data:后面的数据直接用做网页的内容,而不是网页的地址。

简单的说,data类型的Url大致有下面几种形式。

data:,<文本数据>
data:text/plain,<文本数据>
data:text/html,<HTML代码>
data:text/html;base64,<base64编码的HTML代码>
data:text/css,<CSS代码>
data:text/css;base64,<base64编码的CSS代码>
data:text/javascript,<Javascript代码>
data:text/javascript;base64,<base64编码的Javascript代码>
data:image/gif;base64,base64编码的gif图片数据
data:image/png;base64,base64编码的png图片数据
data:image/jpeg;base64,base64编码的jpeg图片数据
data:image/x-icon;base64,base64编码的icon图片数据

因为Url是一种基于文本的协议,所以gif/png/jpeg这种二进制属于需要用base64进行编码。换句话说,引入base64以后,就可以支持任意形式的数据格式。下面是个png图片的例子,会在浏览器中显示一个Mozilla的图标。

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==

data格式Url的种种应用举例

可以在Html的Img对象中使用,例如

<img src="data:image/x-icon;base64,AAABAAEAEBAAAAAAAABoBQAAF..." />

可以在Css的background-image属性中使用,例如

div.image {
  width:100px;
  height:100px;
  background-image:url(data:image/x-icon;base64,AAABAAEAEBAAAAAAAABoBQAAF...);
}

可以在Html的Css链接处使用,例如

<link rel="stylesheet" type="text/css"
  href="data:text/css;base64,LyogKioqKiogVGVtcGxhdGUgKioq..." />

可以在Html的Javascript链接处使用,例如

<script type="text/javascript"
  href="data:text/javascript;base64,dmFyIHNjT2JqMSA9IG5ldyBzY3Jv..."></script>

完整的语法定义

在RFC中,完整的语法定义如下。

dataurl    := "data:" [ mediatype ] [ ";base64" ] "," data
mediatype  := [ type "/" subtype ] *( ";" parameter )
data       := *urlchar
parameter  := attribute "=" value]]

urlchar指的就是一般url中允许的字符,有些字符需要转义,例如"="要转义为"%3D",不过我测试下来,至少在Firefox里面,不转义也是可以的。

parameter可以对mediatype进行属性的扩展,常见的是charset,用来定义编码格式,在多语言情况下需要用到。例如下面的例子。

data:text/plain;charset=UTF-8;base64,5L2g5aW977yM5Lit5paH77yB

这个例子会显示出"你好,中文!"。如果吧charset部分去掉,就会显示乱码,因为我用的是UTF-8编码。

Firefox有一个data类型Url的测试页面,列出了各种格式的data类型Url的测试Url,和测试结果说明。

base64编码和内容的隐秘

把二进制数据转换成为Base64不是什么难事,比如Total Commander就有这样的功能。还有一些在线资源,

有些在线转换把base64里面的“=”转换成为%3D,这个在Url中和“=”是一样的,不转换也没什么问题。

当然,这种Url还有一种隐秘的好处,就是将一些道貌岸然者不喜欢的东西,堂而皇之的放在页面上,例如下面这个数据。你可以Copy下来贴到地址栏里面去瞅瞅,呵呵呵:o)

data:image/jpeg;base64,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


ref:www.bobopo.com/article/code/data_url.htm