Archive for the ‘Actionscript’ Category

強制結束DragManager

Thursday, July 23rd, 2009
DragManagerImpl#endDrag();

見:DragManagerImpl.as
由於原本的DragManager實作了IDragManager,裡面並沒有公開endDrag()此signature,因此你必須轉型之後才能呼叫這個方法。

清除預設的DragEvent外觀效果

Friday, May 22nd, 2009

針對Flex 預設的Drag-Drop,List元件會貼心地幫你畫出indicator(預設是一條線),然而,一旦試著用 DragEvent#preventDefault()時,indicator 會殘留在畫面上,此時,可以利用

ListBase#hideDropFeedback(event:DragEvent)

即可清除掉indicator, highlight 等 DisplayObject.

==
To clean up Flex default DragDrop visualization, try ListBase#hideDropFeedback(event), Especially when implementing your own drag-drop event handlers. This method remove all highlight and indicator display objects.

英文單字單複數互轉(Actionscript Inflection Utility)

Tuesday, May 19th, 2009

模仿Rails的Inflection方法,用actionscript 改寫如下:

Inflection#singularize : 將複數轉單數

如:
Inflection.singularize( “cars” ); //cars => car

Inflection#pluralize : 將單數轉複數

如:
Inflection.pluralize( “apple” ); // apple => apples

原始碼如下:(source)

package net.shiue.util
{
public class Inflection
    {
        public function Inflection()
        {
        }
       
        public static function pluralize( word:String ):String
        {
           
            if( isUncountable( word ) )
                return word;
           
            for each( var r:Replacer in plurals )
            {
                if( word.search( r.pattern ) >= 0 )
                    return word.replace( r.pattern , r.repalcePattern );
            }
           
            return word;
        }
       
        public static function singularize( word:String ):String
        {
           
            if( isUncountable( word ) )
                return word;
           
           
            for each( var r:Replacer in singulars )
            {
                if( word.search( r.pattern ) >= 0 )
                    return word.replace( r.pattern , r.repalcePattern );
            }
           
            return word;
        }
       
        private static var _plurals:Array;
       
        private static function get plurals():Array
        {
           
            if( _plurals == null )
            {
                _plurals = [];
               
                _plurals.push( new Replacer( /(quiz)$/i , "$1zes" ) );
                _plurals.push( new Replacer( /^(ox)$/i , "$1en" ) );
                _plurals.push( new Replacer( /([m|l])ouse$/i , "$1ice" ) );
                _plurals.push( new Replacer( /(matr|vert|ind)(?:ix|ex)$/i , "$1ices" ) );
                _plurals.push( new Replacer( /(x|ch|ss|sh)$/i , "$1es" ) );
                _plurals.push( new Replacer( /([^aeiouy]|qu)y$/i , "$1ies" ) );
                _plurals.push( new Replacer( /(hive)$/i , "$1s" ) );
                _plurals.push( new Replacer( /(?:([^f])fe|([lr])f)$/i , "$1$2ves" ) );
                _plurals.push( new Replacer( /sis$/i , "ses" ) );
                _plurals.push( new Replacer( /([ti])um$/i , "$1a" ) );
                _plurals.push( new Replacer( /(buffal|tomat)o$/i , "$1oes" ) );
                _plurals.push( new Replacer( /(bu)s$/i , "$1ses" ) );
                _plurals.push( new Replacer( /(alias|status)$/i , "$1es" ) );
                _plurals.push( new Replacer( /(octop|vir)us$/i , "$1i" ) );
                _plurals.push( new Replacer( /(ax|test)is$/i , "$1es" ) );
                _plurals.push( new Replacer( /s$/i , "s" ) );
                _plurals.push( new Replacer( /$/i , "s" ) );
               
            }
           
            return _plurals;
        }
       
        private static var _singulars:Array;
       
        private static function get singulars():Array
        {
            if( _singulars == null )
            {
                _singulars  = [];
               
                _singulars.push( new Replacer(/(database)s$/i , "$1") );
                _singulars.push( new Replacer(/(quiz)zes$/i , "$1") );
                _singulars.push( new Replacer(/(matr)ices$/i , "$1ix") );
                _singulars.push( new Replacer(/(vert|ind)ices$/i , "$1ex") );
                _singulars.push( new Replacer(/^(ox)en/i , "$1") );
                _singulars.push( new Replacer(/(alias|status)es$/i, "$1") );
                _singulars.push( new Replacer(/(octop|vir)i$/i, "$1us") );
                _singulars.push( new Replacer(/(cris|ax|test)es$/i, "$1is") );
                _singulars.push( new Replacer(/(shoe)s$/i, "$1") );
                _singulars.push( new Replacer(/(o)es$/i, "$1") );
                _singulars.push( new Replacer(/(bus)es$/i, "$1") );
                _singulars.push( new Replacer(/([m|l])ice$/i, "$1ouse") );
                _singulars.push( new Replacer(/(x|ch|ss|sh)es$/i, "$1") );
                _singulars.push( new Replacer(/(m)ovies$/i, "$1ovie") );
                _singulars.push( new Replacer(/(s)eries$/i, "$1eries") );
                _singulars.push( new Replacer(/([^aeiouy]|qu)ies$/i, "$1y") );
                _singulars.push( new Replacer(/([lr])ves$/i, "$1f") );
                _singulars.push( new Replacer(/(tive)s$/i, "$1") );
                _singulars.push( new Replacer(/(hive)s$/i, "$1") );
                _singulars.push( new Replacer(/([^f])ves$/i, "$1fe") );
                _singulars.push( new Replacer(/(^analy)ses$/i, "$1sis") );
                _singulars.push( new Replacer(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, "$1$2sis") );
                _singulars.push( new Replacer(/([ti])a$/i, "$1um") );
                _singulars.push( new Replacer(/(n)ews$/i, "$1ews") );
                _singulars.push( new Replacer(/s$/i, "") );
               

            }
           
            return _singulars;
           
        }
       
        private static var _irregular:Array;
       
        private static function get irregular():Array
        {
            if( _irregular == null )
            {
                _irregular = [];
               
                _irregular.push( new Replacer(/person/i , "people") );
                _irregular.push( new Replacer(/man/i , "men") );
                _irregular.push( new Replacer(/woman/i , "women") );
                _irregular.push( new Replacer(/child/i , "children") );
                _irregular.push( new Replacer(/sex/i , "sexes") );
                _irregular.push( new Replacer(/move/i , "moves") );
                _irregular.push( new Replacer(/cow/i , "kine") );
            }
           
            return _irregular;
        }
           
        private static var _uncountable:Array;
       
        private static function get uncountable():Array
        {
            if( _uncountable == null )
            {
                _uncountable = [];
               
                _uncountable.push("equipment");
                _uncountable.push("information");
                _uncountable.push("rice");
                _uncountable.push("money");
                _uncountable.push("species");
                _uncountable.push("series");
                _uncountable.push("fish");
                _uncountable.push("sheep");
               
            }
           
            return _uncountable;
        }
       
        public static function isUncountable( word:String ):Boolean
        {
            return uncountable.indexOf( word )>=0;
        }

    }
   
   
}
   

    class Replacer
    {
        public function Replacer( pattern:RegExp , replacePattern:String )
        {
            this.pattern = pattern;
            this.repalcePattern = replacePattern;
        }
       
        public var pattern:RegExp;
        public var repalcePattern:String;
    }

製作蘋果電腦的標題列外皮(Mac title bar skin)

Tuesday, May 12th, 2009

Mac的比較漂亮啦 !

剛剛研究出快速畫出Mac標題列的樣式,這麼做:
建立自己的ProgramaticSkin, 覆寫 updateDisplayList( w , h );

override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList( unscaledWidth , unscaledHeight );
var g:Graphics = graphics;
g.clear();

var m:Matrix = verticalGradientMatrix( 0 , 0 , unscaledWidth , unscaledHeight );
drawRoundRect( 0 , 0 , unscaledWidth , unscaledHeight , { tl:6,tr:6,bl:0,br:0 } ,
          [ 0xC5C5C5 , 0x969696 ] , [1,1] ,m , GradientType.LINEAR , [0,255] );

}

AIR 程式效能調校技巧

Thursday, May 7th, 2009

更新@2009/5/11:
Adobe 有個驅動Garbage Collection的方法:

flash.system.System.gc();
flash.system.System.gc();

但是必須連續呼叫兩次,第一次呼叫: 對物件加上記號;第二次:清除記憶體
更多詳情請見:
http://www.craftymind.com/2008/04/09/kick-starting-the-garbage-collector-in-actionscript-3-with-air/


原文:
http://blogs.adobe.com/air/2009/05/performance_tips_for_adobe_air.html

在處理Grant Skinner發現的CPU效能問題之前,有幾個方法可以先改善AIR程式的效能:

  1. 盡可能地減少frameRate
  2. Grant Skinner提供了一個小程式,監聽 AIREvent.APPLICATION_DEACTIVE事件(該事件在AIR的native window失去focus時會觸發; 重新得到focus時,會觸發 APPLICATION_ACTIVE),自動將frameRate降至 1 ,可以看他的文章: http://www.gskinner.com/blog/archives/2009/05/idle_cpu_usage.html
  3. 盡可能用Timer; 而不是監聽EVENT.ENTER_FRAME做處理
  4. 用profiler 查看Flex app吧

更多文章:

偵測swf的安全漏洞: SWFScan

Thursday, March 26th, 2009

HP 推出可以偵測swf檔的安全漏洞的程式: SWFScan
可到HP官網免費下載!

少用File#nativePath, 用File#url

Sunday, March 22nd, 2009

File.nativePath 是完整的絕對路徑,如果直接用nativePath的值當作路徑,在mac上有時會出現IOError。然而,File.url 會把applicationStorage的路徑用app-storage: 替換掉,參照的時候再轉換,對於不同的系統結構,用File.url是比較保險的作法。

var docs:File = File.applicationStorageDirectory;
trace(docs.nativePath); // C:\Documents and Settings\user\Application Data\my_air\Local Store\
trace(docs.url); // app-storage:/

一次展開Tree元件的所有節點(Expand All Children of Tree)

Sunday, March 22nd, 2009

展開一個Tree元件的所有節點的方法,有兩個階段:
1. 走訪所有節點
2. 如果是枝幹(branch)結點,就打開它( 有預設的方法可以使用, expandChildrenOf( node, open) )

要提醒的地方是,所有ListBase類型的元件,裡頭都有一個collectionChangeHandler的涵式,我們可以複寫他,讓每次資料重讀之後,就打開全部節點。
請見下方原始碼 :)

===
All ListBase-components handle collection with a collectionChangeHandler(event). All we have to do is override it by adding a expandAll() function. How will we do with this expandAll()? See following sample:

override protected function collectionChangeHandler(event:Event):void
{
    super.collectionChangeHandler( event );
   
    if( expandChildrenAfterReset )
    {
        if( CollectionEvent( event ).kind == CollectionEventKind.RESET )
        {
            expandAll();
        }
    }
}


public function expandAll():void
{
    if( collection )
    {
        var c:IViewCursor = collection.createCursor();
        var o:Object;
        while( !c.afterLast )
        {  
            o = c.current;
           
            if( dataDescriptor.isBranch( o ) )
                expandChildrenOf( o ,true );

            c.moveNext();
        }
    }
}

As you see, we just iterate all tree node, determining if it is a branch and then call the built-in expandChildreOf(node,open) method.

Drag and Drop on AIR.HTML Using NativeDragManager

Wednesday, March 4th, 2009

DOM object in HTML ( HTML.domWindow ) stop the Drag events propagating so that dragging over HTML ui will not succeed, which means you cannot see an accept-drop-icon near mouse cursor. To solve this, you have to register a handler to prevent DOM doing something behind but accept drop action, as following sample code:

myHtml.domWindow.document.addEventListener( "dragover:", onDomDragOver );
function onDomDragOver( e:* ):void
{
e.preventDefault();
NativeDragManager.acceptDragDrop( this );
}

試圖用NativeDragManager拖拉外部物件到Air時,如果遇到HTML元件,會出現無法acceptDragDrop的情況,此時,必須針對HTML#htmlLoader底下的DOM 物件監聽 dragover/dragenter 等javascript事件,阻止DOM自己的事件處理,並在此時,命令HTML接受dragDrop,請見上方原始碼。

PS: Javascript drag event types:
dragover
dragenter
drop

ex: getElementById( “myBox” ).addEventListener( “dragover” , onOverBox );

消失的BarSeries標籤文字 - Missing Labels on Bar Series

Thursday, December 11th, 2008

[更新@2008.12.16]
關於更改Series上的label,修改InstanceCache宣告會更快更好:

/**
*To manipulate label instances on series, overridding the instanceCache object  is a better approach.
**/

labelCache = new InstanceCache( Label , labelContainer )
labelCache.property = { truncateToFit : false };

使用Bar Chart 的時候,有個現象:
當Bar上頭的標籤文字太長,以至於無法放進畫面中,BarChart 會清除掉裡面的文字內容:
label.text = “”; (請見BarChart.as line 662)
好在,它只是清掉renderData的cache,並非真正的dataProvider內容(如果是,就糟了),也因此,我們有機會把這些文字回覆,逼它無論如何都要顯示,方法很簡單,你可以自訂一個BarSeries,請見如下程式碼。走訪dataprovider,把值塞回去給Label 實體即可,但請確保文字框夠大,或是把truncateToFit改成false,這樣就不會被裁切掉了。

[English version]
A Bar-Chart renders several series where those labels show up. If you have read source of BarChart.as, you would aware of one thing: If by checking the TextField width against remaining space, there is no enough space to place the label , the label text will be eliminated. ( see source: BarChart.as Line 662 ) However, I think Adobe team might do too much here so that even if you set explicit textField width with a very large number, it won’t work. Fortunately, BarChart itself clear the renderCache instead of dataprovider so that we could recover the text of each label. Here is an example:

// extends BarSeries

//override updateDisplayList()
override protected function updateDisplayList( w:Number , h:Number )
{
super.udpateDisplayList( w , h );
//here we get all created *Label* instances
var labels:Array = labelCache.instances;
// cursor is a IViewCursor, iterating the dataprovider so that cursor#view is just dataprovider object.
var dataList:Array = IList( cursor.view ).toArray();
var len:int = labels.length;
//iterate all label instance, if the text is removed, re-assign it and validate as well.
//one more thing, the length of labels and dataprovider should be the same.
       var label:Label;
    for(var i:int = 0 ; i < len ; i++ )
    {
        label = Label( labels[i] );
        if( label )
        {
            label.truncateToFit = false; //optional
            label.width = Math.max(w,300); //optional
           
            if( label.text == "" && labelFunction != null )
            {
                var c:ChartItem = ChartItem( items[i] );
                c.item = v[i];
                var txt:String = this.labelFunction( c , this )
                label.text = txt;
            }
           
            label.validateNow();
        }  
}