2008年1月25日 星期五

Flex Chart 技巧 - 移除浮水印   [+/-]

Ticore's Blog

Flex Chart 雖然有提供完整的試用功能
不過編譯完成的圖表會加上浮水印

Flex Data Visualization Trial

以上的浮水印其實是以 AS3 動態加上的
既然是 AS,那事情就簡單了
只要在 Flex Project 內自行加上以下 Class

ChartsLicenseHandler Class:

package mx.charts.chartClasses {
 public class ChartsLicenseHandler {
 }
}
// Ticore's Blog - http://ticore.blogspot.com/

然後在 MXML 內明確引用該 Class,或是用 Metadata Tag 強迫編譯
這樣就可以去除浮水印了~!

<?xml version="1.0"?>
<mx:Application backgroundColor="#DDDDDD"
  xmlns:mx="http://www.adobe.com/2006/mxml">
 <mx:Script>
  <![CDATA[
  
  [Frame(extraClass="mx.charts.chartClasses.ChartsLicenseHandler")]
  
  import mx.collections.ArrayCollection;
  
  [Bindable]
  private var expensesAC:ArrayCollection = new ArrayCollection( [
   { Month: "Jan", Profit: -200, Expenses: 1500, Amount: 500 },
   { Month: "Feb", Profit: 1000, Expenses: 200, Amount: 600 },
   { Month: "Mar", Profit: 1500, Expenses: -500, Amount: 300 } ]);
  ]]>
 </mx:Script>

 <mx:SolidColor id="sc1" color="blue" alpha=".3"/>
 <mx:SolidColor id="sc2" color="red" alpha=".3"/>
 <mx:SolidColor id="sc3" color="green" alpha=".3"/>

 <mx:Stroke id="s1" color="blue" weight="1"/>
 <mx:Stroke id="s2" color="red" weight="1"/>
 <mx:Stroke id="s3" color="green" weight="1"/>

 <mx:Panel title="PlotChart Control Example" height="100%" width="100%">
  <mx:PlotChart id="plot" height="100%" width="100%"
    paddingLeft="5" paddingRight="5"
    showDataTips="true" dataProvider="{expensesAC}" >
   <mx:series>
    <mx:PlotSeries xField="Expenses" yField="Profit"
     displayName="Plot 1" fill="{sc1}" stroke="{s1}" />
    <mx:PlotSeries xField="Amount" yField="Expenses"
     displayName="Plot 2" fill="{sc2}" stroke="{s2}" />
    <mx:PlotSeries xField="Profit" yField="Amount"
     displayName="Plot 3" fill="{sc3}" stroke="{s3}" />
   </mx:series>
  </mx:PlotChart>
 </mx:Panel>
</mx:Application>

相關連結:
Flex AdvancedDataGrid 技巧 - 移除浮水印

Read more...

2008年1月14日 星期一

Flex 技巧 - 讓 Canvas 也能表現負數座標的物件   [+/-]

Ticore's Blog

2008/04/11 更新,修正滑鼠滾輪捲動 Bug

Flex 技巧 - 對齊中心縮放 Part 2
強迫容器內所有物件都要位於零或是正數座標上
避免 Canvas 內的物件對齊中心縮放時不會被截掉
但是不適合用在多個物件情況

另外,Flex Canvas 本身也無法呈現位於負數座標軸的物件
所以花了很多時間觀察 Flex Canvas、Container 程式碼
想辦法調整 Canvas 行為,讓它可以呈現負數座標軸的物件
加上之前覆寫的 validateDisplayList 就可以更完美的縮放視野

Flex 線上範例:


AdvancedCanvas Class:

/*
 Ticore's Blog
 http://ticore.blogspot.com/
*/
package com.ticore.uicomponents {
 
 import flash.geom.*;
 
 import mx.containers.Canvas;
 import mx.core.*;

 use namespace mx_internal;

 public class AdvancedCanvas extends Canvas {
  
  public function AdvancedCanvas() {
   super();
  }
  
  override mx_internal function getScrollableRect():Rectangle{
   var rect:Rectangle = super.getScrollableRect();
   
   // Negative coordinates force clip content
   rect.x = -1E-323;
   rect.y = -1E-323;
   return rect;
  }
  
  override protected function scrollChildren():void{
   super.scrollChildren();
   
   // Offset scrollPosition
   if (contentPane && contentPane.scrollRect) {
    var bounds:Rectangle = super.getScrollableRect();
    var sRect:Rectangle = contentPane.scrollRect;
    sRect.offset(bounds.x, bounds.y);
    contentPane.scrollRect = sRect;
   }
  }
  
  override public function validateDisplayList():void{
   var centerPercentX:Number = 0;
   var centerPercentY:Number = 0;
   
   // Record scrollPosition percent
   if (maxHorizontalScrollPosition > 0) {
    centerPercentX = horizontalScrollPosition / maxHorizontalScrollPosition;
   } else {
    centerPercentX = 0.5;
   }
   
   if (maxVerticalScrollPosition > 0) {
    centerPercentY = verticalScrollPosition / maxVerticalScrollPosition;
   } else {
    centerPercentY = 0.5;
   }
   
   super.validateDisplayList();
   
   // Restore scrollPosition percent
   if (maxHorizontalScrollPosition > 0) {
    var newHScrollPosition:Number = maxHorizontalScrollPosition * centerPercentX;
    newHScrollPosition = newHScrollPosition > 0 ? newHScrollPosition : 0;
    newHScrollPosition = newHScrollPosition < maxHorizontalScrollPosition ?
      newHScrollPosition : maxHorizontalScrollPosition;
    horizontalScrollPosition = newHScrollPosition;
   }
   
   if (maxVerticalScrollPosition > 0) {
    var newVScrollPosition:Number = maxVerticalScrollPosition * centerPercentY;
    newVScrollPosition = newVScrollPosition > 0 ? newVScrollPosition : 0;
    newVScrollPosition = newVScrollPosition < maxVerticalScrollPosition ?
      newVScrollPosition : maxVerticalScrollPosition;
    verticalScrollPosition = newVScrollPosition;
   }
  }
  
 }
}

Flex MXML:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
  xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:comp="com.ticore.uicomponents.*"
  width="100%" height="100%" layout="vertical"
  backgroundColor="#E0E0E0" themeColor="#000000" fontSize="11">
 <mx:Script>
  <![CDATA[
   [Bindable]
   [Embed(source='../assets/assets.swf', symbol='Murex')]
   public var img:Class;
  ]]>
 </mx:Script>
 <mx:ApplicationControlBar dock="true">
  <mx:LinkBar width="100%" dataProvider="{viewStack}" />
 </mx:ApplicationControlBar>
 
 <mx:ViewStack id="viewStack" width="100%" height="100%">
 
  <mx:VBox width="100%" height="100%" label="Sample 1">
   <mx:Label text="Align Center & Zooming by Center" />
   <comp:AdvancedCanvas borderColor="#808080" borderStyle="inset"
     width="100%" height="100%">
    <mx:Image horizontalCenter="0" verticalCenter="0" source="{img}"
     scaleX="{zoomSlider.value}" scaleY="{zoomSlider.value}" />
   </comp:AdvancedCanvas>
  </mx:VBox>
 
  <mx:VBox width="100%" height="100%" label="Sample 2">
   <mx:Label text="Two Images Offset Center" />
   <comp:AdvancedCanvas
     borderColor="#808080" borderStyle="inset"
     width="100%" height="100%">
    <mx:Image horizontalCenter="-50" verticalCenter="-25"
     alpha="0.7" source="{img}"
     scaleX="{zoomSlider.value}" scaleY="{zoomSlider.value}" />
    <mx:Image horizontalCenter="50" verticalCenter="25"
     alpha="0.7" source="{img}"
     scaleX="{zoomSlider.value}" scaleY="{zoomSlider.value}" />
   </comp:AdvancedCanvas>
  </mx:VBox>
 
  <mx:VBox width="100%" height="100%" label="Sample 3">
   <mx:Label text="Two Images with Negative Coordinates" />
   <comp:AdvancedCanvas
     borderColor="#808080" borderStyle="inset"
     width="100%" height="100%">
    <mx:Image x="-100" y="-50" alpha="0.7" source="{img}"
     scaleX="{zoomSlider.value}" scaleY="{zoomSlider.value}" />
    <mx:Image x="100" y="50" alpha="0.7" source="{img}"
     scaleX="{zoomSlider.value}" scaleY="{zoomSlider.value}" />
   </comp:AdvancedCanvas>
  </mx:VBox>
  
 </mx:ViewStack>
 
 <mx:HSlider id="zoomSlider" width="100%" liveDragging="true"
  labels="['0.1x', '3x','6x']" tickValues="[0.1, 1, 2, 3, 4, 5, 6]"
  value="0.3" minimum="0.1" maximum="6" tickInterval="1" />
  
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

相關連結:
Flex 技巧 - 對齊中心縮放
Flex 技巧 - 對齊中心縮放 Part 2

Read more...

2008年1月11日 星期五

Flex 技巧 - 對齊中心縮放 Part 2   [+/-]

Ticore's Blog

2008/04/11 更新,修正滑鼠滾輪捲動 Bug

上次 Flex 技巧 - 對齊中心縮放
嘗試用 verticalCenter="0" horizontalCenter="0" 屬性
讓物件能在 Canvas 內對齊中心,並且縮放
可是 verticalCenter、horizontalCenter 的 Layout 行為似乎有些問題
只要是物件位於負數座標部分,都無法正常顯示

這次覆寫 Canvas.updateDisplayList 方法
強迫容器內所有物件都要位於零或是正數座標上
這樣就可以利用 verticalCenter="0" horizontalCenter="0" 屬性
讓 Canvas 內的物件對齊中心縮放,不會被截掉
也不用額外嵌套 Box 容器
垂直捲軸與水平捲軸可以正常的獨立運作

Flex 線上範例:


CenterCanvas Class:

/*
 Ticore's Blog
 http://ticore.blogspot.com/
*/
package com.ticore.uicomponents {
 
 import flash.geom.*;
 
 import mx.core.*;
 import mx.containers.Canvas;

 use namespace mx_internal;

 public class CenterCanvas extends Canvas {
  
  public function CenterCanvas() {
   super();
  }
  
  override protected function updateDisplayList(
    unscaledWidth:Number, unscaledHeight:Number):void{
   
   super.updateDisplayList(unscaledWidth, unscaledHeight);
   
   var child:UIComponent, x:Number, y:Number;
   for (var i:Number = 0 ; i < numChildren ; i++) {
    child = getChildAt(i) as UIComponent;
    if (!child) {
     continue;
    }
    if (!isNaN(child.getStyle("horizontalCenter"))) {
     x = child.x < 0 ? 0 : child.x;
    } else {
     x = child.x;
    }
    if (!isNaN(child.getStyle("verticalCenter"))) {
     y = child.y < 0 ? 0 : child.y;
    } else {
     y = child.y;
    }
    child.move(x, y);
   }
  }
  
  override public function validateDisplayList():void{
   var centerPercentX:Number = 0;
   var centerPercentY:Number = 0;
   
   // Record scrollPosition percent
   if (maxHorizontalScrollPosition > 0) {
    centerPercentX = horizontalScrollPosition / maxHorizontalScrollPosition;
   } else {
    centerPercentX = 0.5;
   }
   
   if (maxVerticalScrollPosition > 0) {
    centerPercentY = verticalScrollPosition / maxVerticalScrollPosition;
   } else {
    centerPercentY = 0.5;
   }
   
   super.validateDisplayList();
   
   // Restore scrollPosition percent
   if (maxHorizontalScrollPosition > 0) {
    var newHScrollPosition:Number = maxHorizontalScrollPosition * centerPercentX;
    newHScrollPosition = newHScrollPosition > 0 ? newHScrollPosition : 0;
    newHScrollPosition = newHScrollPosition < maxHorizontalScrollPosition ?
      newHScrollPosition : maxHorizontalScrollPosition;
    horizontalScrollPosition = newHScrollPosition;
   }
   
   if (maxVerticalScrollPosition > 0) {
    var newVScrollPosition:Number = maxVerticalScrollPosition * centerPercentY;
    newVScrollPosition = newVScrollPosition > 0 ? newVScrollPosition : 0;
    newVScrollPosition = newVScrollPosition < maxVerticalScrollPosition ?
      newVScrollPosition : maxVerticalScrollPosition;
    verticalScrollPosition = newVScrollPosition;
   }
  }
  
 }
}

Flex MXML:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
  xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:comp="com.ticore.uicomponents.*"
  width="100%" height="100%" layout="vertical"
  backgroundColor="#E0E0E0" themeColor="#000000" fontSize="11">
 <comp:CenterCanvas borderColor="#808080" borderStyle="inset"
   width="100%" height="100%">
  <mx:Image horizontalCenter="0" verticalCenter="0"
   source="@Embed(source='../assets/assets.swf', symbol='Murex')"
   scaleX="{zoomSlider.value}" scaleY="{zoomSlider.value}" />
 </comp:CenterCanvas>
 <mx:HSlider id="zoomSlider" width="100%" liveDragging="true"
  labels="['0.1x', '3x', '6x']" tickValues="[0.1, 1, 2, 3, 4, 5, 6]"
  value=".5" minimum="0.1" maximum="6" tickInterval="1" />
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

相關連結:
Flex 技巧 - 對齊中心縮放
Flex 技巧 - 讓 Canvas 也能表現負數座標的物件

Read more...

2008年1月8日 星期二

Flex 技巧 - 對齊中心縮放   [+/-]

Ticore's Blog

2008/04/11 更新,修正滑鼠滾輪捲動 Bug

Flex 目前常用的 Container 中
當內容物大小發生變化導致捲軸出現時
Container View 的位置都是以左上角為對齊基準
(見下面 Flex 範例 Sample 1)

而 Box 容器雖然可以讓物件水平、垂直置中對齊
但是會隨著內容物大小撐大
這樣就不能用捲軸捲動視野,不適合使用

除此之外,沒有其它容器可以用來作對齊中心縮放

於是自行覆寫 Canvas.validateDisplayList,控制捲軸的行為
讓內容物大小改變時,容器能夠依據視野的中心捲動
(見下面 Flex 範例 Sample 2)

不過當內容物大小小於容器大小時,捲軸沒有作用
Canvas 也沒有直接置中的功能可以使用
所以再利用一個 Box 嵌套,達到水平、垂直置中對齊功能
不過有一個小缺點,垂直、水平捲軸自動出現行為是綁在一起的
(見下面 Flex 範例 Sample 3)

內容物大小小於容器大小時
也可以指定物件本身 verticalCenter="0" horizontalCenter="0" 屬性
來作置中對齊,而且垂直、水平捲軸自動出現行為是獨立的
不過當捲軸出現時,物件的上方與左方會被切掉
(見下面 Flex 範例 Sample 4)

Flex 線上範例:


Flex 範例程式碼:

MyCanvas:

/*
 Ticore's Blog
 http://ticore.blogspot.com/
*/
package com.ticore.uicomponents {
 
 import flash.geom.*;
 
 import mx.containers.Canvas;

 public class MyCanvas extends Canvas {
  
  public function MyCanvas() {
   super();
  }
  
  override public function validateDisplayList():void{
   
   var centerPercentX:Number = 0;
   var centerPercentY:Number = 0;
   
   if (maxHorizontalScrollPosition > 0) {
    centerPercentX = horizontalScrollPosition / maxHorizontalScrollPosition;
   } else {
    centerPercentX = 0.5;
   }
   
   if (maxVerticalScrollPosition > 0) {
    centerPercentY = verticalScrollPosition / maxVerticalScrollPosition;
   } else {
    centerPercentY = 0.5;
   }
   
   super.validateDisplayList();
   
   // Restore scrollPosition percent
   if (maxHorizontalScrollPosition > 0) {
    var newHScrollPosition:Number = maxHorizontalScrollPosition * centerPercentX;
    newHScrollPosition = newHScrollPosition > 0 ? newHScrollPosition : 0;
    newHScrollPosition = newHScrollPosition < maxHorizontalScrollPosition ?
      newHScrollPosition : maxHorizontalScrollPosition;
    horizontalScrollPosition = newHScrollPosition;
   }
   
   if (maxVerticalScrollPosition > 0) {
    var newVScrollPosition:Number = maxVerticalScrollPosition * centerPercentY;
    newVScrollPosition = newVScrollPosition > 0 ? newVScrollPosition : 0;
    newVScrollPosition = newVScrollPosition < maxVerticalScrollPosition ?
      newVScrollPosition : maxVerticalScrollPosition;
    verticalScrollPosition = newVScrollPosition;
   }
  }
 }
}

Flex MXML:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
  xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:comp="com.ticore.uicomponents.*"
  width="100%" height="100%" layout="vertical"
  backgroundColor="#E0E0E0" themeColor="#000000" fontSize="11">
 <mx:Script>
  <![CDATA[
   [Bindable]
   [Embed(source='../assets/assets.swf', symbol='Murex')]
   public var img:Class;
  ]]>
 </mx:Script>
 <mx:ApplicationControlBar dock="true">
  <mx:LinkBar width="100%" dataProvider="{viewStack}" />
 </mx:ApplicationControlBar>
 
 <mx:ViewStack id="viewStack" width="100%" height="100%">
  <mx:VBox width="100%" height="100%" label="Sample 1">
   <mx:Label text="Align Top-Left & Zooming by Top-Left" />
   <mx:Canvas borderColor="#808080" borderStyle="inset"
     width="100%" height="100%">
    <mx:Image source="{img}"
     scaleX="{zoomSlider.value}" scaleY="{zoomSlider.value}" />
   </mx:Canvas>
  </mx:VBox>
  <mx:VBox width="100%" height="100%" label="Sample 2">
   <mx:Label text="Align Top-Left & Zooming by Center" />
   <comp:MyCanvas borderColor="#808080" borderStyle="inset"
     width="100%" height="100%" clipContent="true">
    <mx:Image source="{img}"
     scaleX="{zoomSlider.value}" scaleY="{zoomSlider.value}" />
   </comp:MyCanvas>
  </mx:VBox>
  <mx:VBox width="100%" height="100%" label="Sample 3">
   <mx:Label text="Align Center & Zooming by Center" />
   <comp:MyCanvas borderColor="#808080" borderStyle="inset"
     width="100%" height="100%" clipContent="true">
    <mx:Box width="100%" height="100%"
      horizontalAlign="center" verticalAlign="middle">
     <mx:Image source="{img}"
      scaleX="{zoomSlider.value}" scaleY="{zoomSlider.value}" />
    </mx:Box>
   </comp:MyCanvas>
  </mx:VBox>
  <mx:VBox width="100%" height="100%" label="Sample 4">
   <mx:Label text="Align Center & Zooming by Center" />
   <comp:MyCanvas borderColor="#808080" borderStyle="inset"
     width="100%" height="100%" clipContent="true">
    <mx:Image source="{img}" verticalCenter="0" horizontalCenter="0"
     scaleX="{zoomSlider.value}" scaleY="{zoomSlider.value}" />
   </comp:MyCanvas>
  </mx:VBox>
 </mx:ViewStack>
 
 <mx:HSlider id="zoomSlider" width="100%" liveDragging="true"
  labels="['0.1x', '3x','6x']" tickValues="[0.1, 1, 2, 3, 4, 5, 6]"
  value="0.3" minimum="0.1" maximum="6" tickInterval="1" />
  
</mx:Application>
<!-- Ticore's Blog - http://ticore.blogspot.com/ -->

相關連結:
Flex 技巧 - 對齊中心縮放 Part 2
Flex 技巧 - 讓 Canvas 也能表現負數座標的物件

Read more...

2008年1月3日 星期四

Silverlight 技巧 - 讓兩個 Animation 同時作用於單一 X 屬性   [+/-]

Ticore's Blog

在測試 Silverlight XAML 動畫行為時
Storyboard、Animation 功能相當具有彈性
TargetName、TargetProperty 等屬性都可以隨意指定
於是想到是否可以同時用兩個 DoubleAnimation 作用同一個物件的單一屬性上
測試之後,結果是不行的
不是語法無法通過,就是只有最後一個執行的 DoubleAnimation 有效果

不過後來發現 UIElement 可以設定 RenderTransform
而 RenderTransform.TransformGroup 以同時包含多組相同的 Transform
這些 Transform 最後都會被疊加起來
反映到物件的表現上

那麼就可以利用兩個 DoubleAnimation 作用於同一物件下的兩個 TranslateTransform
而這兩個 TranslateTransform 效果同時會反映在該物件的 X 屬性上

以下是 XAML 範例程式:

<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/client/2007"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Width="300" Height="200" x:Name="rootCanvas" Background="Gray">
 <Canvas.Triggers>
  <EventTrigger RoutedEvent="Canvas.Loaded">
   <BeginStoryboard>
    <Storyboard>
     <DoubleAnimation
       Storyboard.TargetName="rect"
       Storyboard.TargetProperty="(Rectangle.RenderTransform).
         (TransformGroup.Children)[0].(TranslateTransform.X)"
       From="0" To="200" Duration="0:0:2"
       AutoReverse="True" RepeatBehavior="Forever"/>
     <DoubleAnimation
       Storyboard.TargetName="rect"
       Storyboard.TargetProperty="(Rectangle.RenderTransform).
         (TransformGroup.Children)[1].(TranslateTransform.X)"
       From="0" To="10" Duration="0:0:0.2"
       AutoReverse="True" RepeatBehavior="Forever"/>
    </Storyboard>
   </BeginStoryboard>
  </EventTrigger>
 </Canvas.Triggers>
 
 <Rectangle x:Name="rect"
  MouseMove="handleMouseMove"
  MouseLeftButtonUp="handleMouseUp" 
  Canvas.Left="30" Canvas.Top="50" Fill="red" 
  Width="50" Height="50">
  <Rectangle.RenderTransform>
   <TransformGroup>
    <TranslateTransform X="0" Y="0" />
    <TranslateTransform X="0" Y="0" />
   </TransformGroup>
  </Rectangle.RenderTransform>
 </Rectangle>
</Canvas>

執行範例

Read more...