<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-67  評論-522  文章-0  trackbacks-0
        本文根據項目實例,詳解如何使用Flex技術開發時空線形圖。
        大象目前從事的是工程管理方面的開發,在土木工程建設行業有一種時空線形圖,它是用實線,虛線,圖形等方式,來描述出工程進度計劃中的數據信息的方法。呈現出來的一般是報表形式,多采用Excel來實現。
        對于客戶來說,手動繪制時空線形圖是比較麻煩的。因為要畫線,畫圖片。如果知道甘特圖或使用過Microsoft Project的朋友應該很快就能明白,對于一個工程的進度計劃來說,它包含有很多的任務項,而這些任務項都需要在線形圖上表示出來,因此手動做的話工作量是很大的。現在有了系統,就可以把這一任務交給計算機來完成,客戶只需要輸入數據即可。
        系統中的時空線形圖最早是采用JavaScript腳本編寫的,后來由我改成了Flex版。先說下實現的思路。因為只是顯示和打印,沒有其它的要與用戶交互的需求。所以后臺數據是直接以XML流文件的形式,通過異步加載獲得。然后再利用Flex強大的XML解析能力處理這些數據,最后就是根據這些數據使用FlashAPI畫圖。呵呵,是不是很簡單? 先看幾張截圖大致了解下。

                
                
                
                

        本文的AS代碼是基于ActionScript 3.0,下面進行詳細說明。
        1、獲得數據
        我采用URLLoader.load方法實現。通過傳遞請求地址,注冊監聽器,然后在回調函數中就可以獲得XML數據了。當然你也可以采用RemoteObject方式。
    public function LoadXML():void {
        
    var loader:URLLoader = new URLLoader();
        
    loader.load(new URLRequest("/baseAction.do?method=ajaxData")); //這個地址可以直接是一個xml文件
        
    loader.addEventListener(Event.COMPLETE, handleComplete);
    }
    private function handleComplete(event:Event):void {
        var xml:XML = new XML(event.target.data);
        
    ……
    }
        這是個異步加載過程,當數據在后臺獲取完成,并轉換為XML格式向前臺發送后,注冊的Event.COMPLETE事件類型就會觸發回調函數handleComplete,然后我們就能得到數據并將它轉型為XML對象。
        2、布局
        我們現在有了數據,下一步就是布局。本項目中的時空線形圖上有這些基本信息:序號、工程名稱、工期、標段劃分和圖例。這其中的工期是一個時間跨度,對應進度計劃的最早開始日期和最晚結束日期。我們取的是年+月的形式來表示。而圖例則是對線形圖中的任務項列出對應的說明。大象當時為了方便,使用FlexGridGridRowGridItem來生成布局框架,要是考慮性能方面的原因,應該換成其它方法實現,因為這種方式速度會有點慢,好在沒有其它的交互情況。那么先讓大象把做法講完,性能調優的話題已經超出本文的范圍了。
        這里就是要不停的生成單元格,由單元格組成行,再由多行組成Grid,這跟html中的tabletrtd是一個道理。

    var grid:Grid = new Grid(); //Grid只需要一個
    var orderRow:GridRow = new GridRow(); //序號行
    var projectRow:GridRow = new GridRow(); //工程名稱行
    ……
        創建了行,我們同時還要向里面添加單元格,也即GridItem。這時就要根據得到的數據來處理了,是一個循環。
    var spaces:* = xml.spaces.space; //可以直接用.符號來獲取XML文件的節點
    for each(var space:Object in spaces){
        orderRow.addChild(createTitleColItem(space.order,space.id)); //循環加載序號

        projectRow.addChild(createVerTitleColItem(space.projectName); //循環加載工程名稱
    }
        createTitleColItemcreateVerTitleColItem里面封裝了單元格的創建,寫成方法方便調用。
        工期的日期時間和標段劃分也是同理,對于工期來說,數據都顯示在最左側一欄,其余的單元格都為空,這樣做是當完成框架布局后,在這空白的區域繪圖。
        好了,到這里布局完成,將grid加入到上一層容器,我用的是Canvas并且將它的寬度和高度設置和grid一樣,然后在Canvas外面再加上一層容器,比如VBox。然后給VBox一個合適的寬高(比較好的做法是取當前顯示器的寬高,否則頁面顯示會有點問題)。讓它比Canvas要小(一般來講,Canvas會比VBox大很多),這時就會出現滾動條,拖動滾動條進行查看。
        3、計算坐標

        在這個應用當中,最重要的應該就是計算坐標了,不管是畫線還是畫圖,都需要坐標來定位。那到底怎么計算坐標呢?其實也不難,通過ID與日期就能把它們算出來。
        ①、X坐標
        注意在設置第一行序號的時候,createTitleColItem(space.order,space.id)這個方法的第二個參數就是一個ID,每個序號項的GridItemid屬性都會保存space.id值,而任務數據項中也有一個這樣的ID,所以就可以通過查找ID來計算出它的水平位置來。
    private function getX(position:String,orderChilds:Array):int{
        var x:int = title_width; //最左側的標題列寬
        for(var i:int=1;i<orderChilds.length-1;i++){
            if((child[i] as GridItem).id==position) break;
            x += col_width; //普通列寬
        }
        return x;
    }
        position是任務項IDorderChilds orderRow.getChildren()得到第一行的所有列返回的數組。任務項中會有兩個position,起始和終止。通過這兩個值可以求出x1x2坐標。
        ②、Y坐標
        y坐標的是通過任務項包含的開始日期和結束日期與整個計劃的最晚日期進行比較計算出來的。
    private function getY(date:Date):int{
        var rowSize:int = 5; //行數,序號和工程名稱占據了五行
        rowSize += Math.abs(dateDiff("m",date,this.endDate));
        var day:int = date.getDate();
        day = day > 30 ? 0 : 30-day;
        return rowSize*title_height+Math.round((day%30/30)*title _height);
    }
        在應用里我將行高都設為相同的值,工程名稱這行是四倍的行高。生成的布局框架里,日期時間是倒排序,它們之間的間隔是一個月。dateDiff就是計算當前日期與最晚日期(this.endDate)之間相隔多少個月,而每相隔一個月,就是一行。因此通過這種方式計算出y坐標。
        我補充說明一下,因為最終展現結果的是Canvas容器,所以坐標的計算都是相對Canvas的,因此這個xy的坐標是相對Canvas內的絕對坐標。

        4、繪圖
        繪圖分為畫線和畫圖形。如果是畫線,則可以直接利用Flashgraphics來畫圖。畫圖形要麻煩點,得先取得圖片,再用圖片來畫圖。不管是畫線還是畫圖形,都是和數據有關的。數據中會有一個類型,是說明到底這個任務項是線還是圖。如果是線,會有一個顏色值,為了防止沒有設置顏色值,我們應該給定一個默認的顏色值。如果是圖,會有個圖片的相對地址,錄數據的時候會上傳圖片,不過為了防止沒有上傳圖片,我們應該準備一個默認圖片。
        ①、畫線
    var line:UIComponent = new UIComponent();
    line.graphics.lineStyle(thickNum,color,1);//設置粗細、顏色、透明度
    line.graphics.moveTo(x1,y1); //從某個坐標開始
    line.graphics.lineTo(x2,y2); //畫到某個坐標
        ②、畫圖
    public function load (url:String,callback:Function,options:*):void{
        var loader:Loader = new Loader();
        loader.load(new URLRequest(encodeURI(url))); //圖片地址
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE,
            function(e:Event):void {callback(e.currentTarget.content,options);});
    }
    load(url,paintRect,{"x1":x1,"y1":y1,"x2":x2,"y2":y2});
    public function paintRect(source:*,options:*):void{
        var shape:UIComponent = new UIComponent();
        var rect_width:int = Math.abs(options.x2–options.x1); //圖形寬度
        var rect_height:int = Math.abs(options.y2–options.y1); //圖形高度
        var bitmap:BitmapData = new BitmapData(source.width, source.height); //用圖片源的寬高定義一個位圖對象
        bitmap.draw(source); //將圖片源在位圖上繪制出來
        shape.graphics.beginBitmapFill(bitmap); //用位圖填充繪圖區域
        shape.graphics.drawRect(options.x1, options.x2,rect_width,rect_height); //定義矩形繪圖區域,這塊區域將用圖片填充
        shape.graphics.endFill(); //應用填充
    }
        load方法就是用來獲取圖片。注冊監聽器,這里我們還是使用Event.COMPLETE事件類型,當圖片加載完成后,會調用回調函數,并將參數也一起傳給回調函數。畫圖工作是在回調函數中進行。另外有一點要說明的是,Loader是用來加載SWF文件或圖像(JPGPNG GIF)文件,URLLoader 類則是加載文本或二進制數據,請大家使用的時候要注意這點區別。
        另外這里不管是畫線還是畫圖都用的是UIComponent類,這是因為它有一個toolTip屬性,當鼠標移至圖或線上時,會顯示你設置的信息。如果用Sprite則沒有這屬性。UIComponentFlex定義的,而Sprite則是Flash本身的。
        畫圖例的方法是一樣的,畫好的圖需要加入到父容器中顯示出來。到此整個做法就講完了,其實也不是很復雜,關鍵是要理清思路。因為涉及到商業項目和保密原則,請原諒大象不能將此源碼拿出來給大家分享,不過我已經提供了部分代碼,而且這些代碼是整個應用中關鍵點。只要大家能從中得到一點幫助,那么我就很滿足了。
        本文為菠蘿大象原創,如要轉載請注明出處。
    posted on 2010-02-25 21:13 菠蘿大象 閱讀(5449) 評論(5)  編輯  收藏 所屬分類: Flex

    評論:
    # re: 使用Flex開發時空線形圖實例詳解 2010-02-25 21:16 | 菠蘿大象
    我今天發現寫掉了一部分,就是第三點,坐標計算,現在補上了,請大家不要怪我又重新發布一次,我希望讓先看過的人再看一下,對不起大家了。  回復  更多評論
      
    # re: 使用Flex開發時空線形圖實例詳解[未登錄] 2010-02-26 12:08 | lazy
    學習一下
    另外能否貼一下xml數據的格式?
    var spaces:* = xml.spaces.space;
    我對這一行代碼也不太明白  回復  更多評論
      
    # re: 使用Flex開發時空線形圖實例詳解 2010-02-26 13:18 | 菠蘿大象
    @lazy
    謝謝提醒,是我疏忽了,我在后臺用jdom封裝xml,具體怎么定義格式完全要看你在應用中怎么方便取值,以及需要用到哪些數據。我帖上應用中的部分
    <?xml version="1.0" encoding="UTF-8"?>
    <project>
    <spaces>
    <space>
    <id>266</id>
    <order>1</order>
    <projectName>金銀潭站</projectName>
    <segment>1標</segment>
    <stationType>1</stationType>
    </space>
    <space>
    <id>267</id>
    <order>2</order>
    <projectName>金常區間</projectName>
    <segment>2標</segment>
    <stationType>2</stationType>
    </space>
    </spaces>
    <tasks>
    <task parent_id="933">
    <id>934</id>
    <name>征地拆遷等前期工程</name>
    <beginDate>2007-09-01</beginDate>
    <endDate>2008-01-01</endDate>
    <shapeState>3</shapeState>
    <position1>266</position1>
    <position2>266</position2>
    <frontColor>#000000</frontColor>
    <backColor>#000000</backColor>
    <designPath>/upload/Image/1238725740078_7741.jpg</designPath>
    </task>
    </tasks>
    </project>  回復  更多評論
      
    # re: 使用Flex開發時空線形圖實例詳解[未登錄] 2010-02-26 13:45 | lazy
    @菠蘿大象

    謝謝,有了xml格式就明白了,原來as里對xml的引用這么方便  回復  更多評論
      
    # re: 使用Flex開發時空線形圖實例詳解 2010-02-26 16:19 | 菠蘿大象
    @lazy
    在ActionScript3.0中,解析xml確實非常方便,要引用屬性可以這樣寫:task.@parent_id,引用元素直接用.(點)。詳細的資料,網上有很多,我就不寫了。  回復  更多評論
      
    主站蜘蛛池模板: 国内自产少妇自拍区免费| 波多野结衣亚洲一级| 国产一级淫片免费播放电影| 一区二区三区四区免费视频 | 国产精品亚洲а∨天堂2021| 亚洲第一成年网站大全亚洲| 国产亚洲人成无码网在线观看| 国产免费私拍一区二区三区| 免费无码又爽又刺激聊天APP| 久久久精品免费视频| 国产三级在线免费观看| 色妞www精品视频免费看| 亚洲色偷偷色噜噜狠狠99| 亚洲精品中文字幕乱码| 亚洲AV午夜福利精品一区二区| 久久亚洲AV永久无码精品| 伊人久久亚洲综合影院| 成年性羞羞视频免费观看无限| 91青青青国产在观免费影视| 免费观看一区二区三区| 国产免费一级高清淫曰本片 | 亚洲色偷偷偷鲁综合| 亚洲va中文字幕无码| 国产免费观看视频| 国产精品无码一二区免费| 女性无套免费网站在线看| 夜夜嘿视频免费看| 女人18毛片水真多免费看| 成人特黄a级毛片免费视频| 久久国内免费视频| 在线观看无码AV网站永久免费| **一级一级毛片免费观看| 99精品免费观看| 亚洲免费观看网站| 免费99精品国产自在现线| 黄页网站免费观看| 美女视频黄的全免费视频| 成**人免费一级毛片| 日本一线a视频免费观看| 免费又黄又爽又猛的毛片| 亚洲婷婷国产精品电影人久久|