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); //循環加載工程名稱
}
createTitleColItem和createVerTitleColItem里面封裝了單元格的創建,寫成方法方便調用。
工期的日期時間和標段劃分也是同理,對于工期來說,數據都顯示在最左側一欄,其余的單元格都為空,這樣做是當完成框架布局后,在這空白的區域繪圖。
好了,到這里布局完成,將grid加入到上一層容器,我用的是Canvas并且將它的寬度和高度設置和grid一樣,然后在Canvas外面再加上一層容器,比如VBox。然后給VBox一個合適的寬高(比較好的做法是取當前顯示器的寬高,否則頁面顯示會有點問題)。讓它比Canvas要小(一般來講,Canvas會比VBox大很多),這時就會出現滾動條,拖動滾動條進行查看。
3、計算坐標
在這個應用當中,最重要的應該就是計算坐標了,不管是畫線還是畫圖,都需要坐標來定位。那到底怎么計算坐標呢?其實也不難,通過ID與日期就能把它們算出來。
①、X坐標
注意在設置第一行序號的時候,createTitleColItem(space.order,space.id)這個方法的第二個參數就是一個ID,每個序號項的GridItem的id屬性都會保存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是任務項ID,orderChilds 是orderRow.getChildren()得到第一行的所有列返回的數組。任務項中會有兩個position,起始和終止。通過這兩個值可以求出x1與x2坐標。
②、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的,因此這個x和y的坐標是相對Canvas內的絕對坐標。
4、繪圖
繪圖分為畫線和畫圖形。如果是畫線,則可以直接利用Flash的graphics來畫圖。畫圖形要麻煩點,得先取得圖片,再用圖片來畫圖。不管是畫線還是畫圖形,都是和數據有關的。數據中會有一個類型,是說明到底這個任務項是線還是圖。如果是線,會有一個顏色值,為了防止沒有設置顏色值,我們應該給定一個默認的顏色值。如果是圖,會有個圖片的相對地址,錄數據的時候會上傳圖片,不過為了防止沒有上傳圖片,我們應該準備一個默認圖片。
①、畫線
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文件或圖像(JPG、PNG 或 GIF)文件,而URLLoader 類則是加載文本或二進制數據,請大家使用的時候要注意這點區別。
另外這里不管是畫線還是畫圖都用的是UIComponent類,這是因為它有一個toolTip屬性,當鼠標移至圖或線上時,會顯示你設置的信息。如果用Sprite則沒有這屬性。UIComponent是Flex定義的,而Sprite則是Flash本身的。
畫圖例的方法是一樣的,畫好的圖需要加入到父容器中顯示出來。到此整個做法就講完了,其實也不是很復雜,關鍵是要理清思路。因為涉及到商業項目和保密原則,請原諒大象不能將此源碼拿出來給大家分享,不過我已經提供了部分代碼,而且這些代碼是整個應用中關鍵點。只要大家能從中得到一點幫助,那么我就很滿足了。
本文為菠蘿大象原創,如要轉載請注明出處。