搜尋此網誌

2009年10月29日 星期四

SilverLight:簡單的Silverlight連續動作(animation)

本篇內容將提到如何使用SilverLight的animation

主要步驟:
a.開啟Silverlight專案
b.新增SilverLight幾何元件
c.編寫animation程式內容

1、開啟一個新的SilverLight專案後,在主要的 xmal 檔中先找到<UserControl>,並在此tag先加入幾個Silverlight元件,在加入Silverlight元件前,我們要求元件做整齊的排列,所以額外請加入一個Grid來排列每個元件。

2、下述<Grid>使用<Ellipse>元件來從事animaltion的動作,我們會對每個<Ellipse>元件加入一個 'onMouseLeftDown' 的屬性,當此元件被按下時,將會觸發 leftDown( ) 函式,以下為需加入xmal檔內<UserControl>的描述。

<Grid x:Name="LayoutRoot">

        <Grid.RowDefinitions>

            <RowDefinition Height="80"/>

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="80"/>

            <ColumnDefinition Width="80"/>

            <ColumnDefinition Width="80"/>

            <ColumnDefinition Width="80"/><!--3-->

            <ColumnDefinition Width="80"/>

            <ColumnDefinition Width="80"/>

            <ColumnDefinition Width="80"/><!--6-->

            <ColumnDefinition Width="80"/>

            <ColumnDefinition Width="80"/><!--8-->

        </Grid.ColumnDefinitions>


        <Ellipse x:Name="e0_0" Width="40" Height="40" StrokeThickness="2" Grid.Row="0" Grid.Column="0"

                 MouseLeftButtonDown="leftDown" >

            <Ellipse.Fill>

                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                    <GradientStop Color="#FFFF7100" Offset="0"/>

                    <GradientStop Color="Yellow" Offset="1"/>

                    <GradientStop Color="#9A86B741" Offset="0.664"/>

                </LinearGradientBrush>

            </Ellipse.Fill>

            <Ellipse.Stroke>

                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                    <GradientStop Color="Black" Offset="0"/>

                    <GradientStop Color="#FFC5B133" Offset="1"/>

                </LinearGradientBrush>

            </Ellipse.Stroke>

        </Ellipse>

        <Ellipse x:Name="e0_1" Width="40" Height="40" StrokeThickness="2" Grid.Row="0" Grid.Column="1"

                 MouseLeftButtonDown="leftDown">

            <Ellipse.Fill>

                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                    <GradientStop Color="#FFFF7100" Offset="0"/>

                    <GradientStop Color="Yellow" Offset="1"/>

                    <GradientStop Color="#9A86B741" Offset="0.664"/>

                </LinearGradientBrush>

            </Ellipse.Fill>

            <Ellipse.Stroke>

                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                    <GradientStop Color="Black" Offset="0"/>

                    <GradientStop Color="#FFC5B133" Offset="1"/>

                </LinearGradientBrush>

            </Ellipse.Stroke>

        </Ellipse>

    </Grid>



 



3、將以上內容需描述在<UserControl>內之後,接著編輯產生animation的程式內容:

private void leftDown(object sender, MouseButtonEventArgs e)
{
Shape s = (Shape)sender;

DoubleAnimation da = new DoubleAnimation();
da.SpeedRatio = 8;
da.From = 40;
da.To = 80;
da.AutoReverse = true;
DoubleAnimation daY = new DoubleAnimation();

daY.SpeedRatio = 8;
daY.From = 40;
daY.To = 80;
daY.AutoReverse = true;

Storyboard sb = new Storyboard();
Storyboard.SetTargetProperty(da, new PropertyPath("(Shape.Width)"));
Storyboard.SetTargetProperty(daY, new PropertyPath("(Shape.Height)"));

Storyboard.SetTarget(sb, s);
Storyboard.SetTargetName(sb, s.Name);//set target name
sb.Children.Add(da);
sb.Children.Add(daY);

sb.Completed += new EventHandler(sb_Completed);
sb.Begin();
}


4、以上敘述為<Ellipse>被按下後,C# 會取得xmal內被觸發此event的元件,將此元件的'Height'屬性及'Width'屬性從40變化至80。

5、其中加入「sb.Complete += new EventHandler(sb_Completed);」,當動作結束後,將會觸發sb_Completed( )這個函式。

6、xmal的敘述中,你會發現每個<Ellipse>元件的命名是有規則的,此用意是為了連續動作的方便而將元件的命名規則化,所以務必在程式中加入下列敘述,以方便在動作結束後,sb_Completed( )敘述能夠取得當下觸發event的元件:

Storyboard.SetTargetName(sb, s.Name);//set target name

7、以下為 sb_Completed( )函式以及 endObj( ) 函式內容:

void sb_Completed(object sender, EventArgs e)
{
string str = Storyboard.GetTargetName(sender as Storyboard);
Shape s = this.FindName(str) as Shape;
string sRow = s.Name.Substring(1, 1);
string sCol = s.Name.Substring(s.Name.Length - 1, 1);
int tmpInt = Int32.Parse(sCol);
tmpInt += 1;
sCol = tmpInt.ToString();
str = "e" + sRow + "_" + sCol;
s = this.FindName(str) as Shape;
if (s != null)
{
nextObj(s,e);
}
else
{
MessageBox.Show("end of shape object !!");
}
}


8、這裡所謂的連續動作,指的是將程式內所有的Silverlight元件以順序而連續animation的方式一一動作。故按下其中一個Silverlight元件後,程式會依序往後抓取下一個<Ellipse>元件,以下請額外加入 nextObj( )函式。

void nextObj(object sender, EventArgs e)
{
Shape s = (Shape)sender;

DoubleAnimation da = new DoubleAnimation();
da.SpeedRatio = 8;
da.From = 40;
da.To = 80;
da.AutoReverse = true;
DoubleAnimation daY = new DoubleAnimation();
daY.SpeedRatio = 8;
daY.From = 40;
daY.To = 80;
daY.AutoReverse = true;

Storyboard sb = new Storyboard();
Storyboard.SetTargetProperty(da, new PropertyPath("(Shape.Width)"));
Storyboard.SetTargetProperty(daY, new PropertyPath("(Shape.Height)"));

Storyboard.SetTarget(sb, s);
Storyboard.SetTargetName(sb, s.Name);//set target name
sb.Children.Add(da);
sb.Children.Add(daY);

sb.Completed += new EventHandler(sb_Completed);
sb.Begin();
}

2009年10月13日 星期二

SVG技巧:正常執行SVG拖曳の動作

Javascript Event 的使用

Javascript中,事件處理常常用到如onmouseclick、onmousemove、onmouseup等動作,在SVG圖象上運用非常頻繁。而使用以上event最簡單的方式即是直接在SVG物件的描述中加入:

onmousedown="function( )"、onmousemove="function( )"、onmouseup="function ( )"

例如在一個SVG四方體物件中:

<rect x="0" y="0" width="100" height="60" fill="red" onmousedown="downFunc()"/>

上述物件就會在被使用者點擊時觸發 downFunc( ) 這個函式。

拖曳動作
1、這裡所謂的「拖曳動作」指的是「按下後隨即移動」的動作,即「mouse down than move」的動作。
2、拖曳動作運用在SVG圖象上會有一種狀況是「SVG圖象被當作是圖片」。使用Firefox對SVG物件做拖曳時,若動作太快(即點擊物件後隨即移動),會被視為「抓取此SVG圖象」的動作。
3、假若程式原本的動作是想要「定點移動SVG圖象」,而非抓取SVG圖象,瀏覽器所產生的錯誤動作實為一大誤會(簡單說就是瀏覽器太雞婆....)。

解決方案一(隱藏後顯示):
說明:
1、即對SVG內容『setAttribute("display","none") 』後,接著『setAttribute("display","inline")』。
2、需注意的是,假若隱藏後隨即顯示將會沒有效果,無法完成原本預期要的動作。
3、需要間隔一小段時間,再將隱藏後的SVG圖象回愎顯示(可使用setTimeout( )來完成)。
4、需配合物件copy的方式來完成。由於主SVG物件從隱藏回愎到顯示時,會明顯發現物件有「閃爍」的動作,感覺非常不自然,在此使用副物件的方式,來製造主物件的分身,產生「無閃爍」的假像。
5、在主SVG物件被隱藏後,滑鼠對於主物件的Focus將會被解除。這樣一來即可避開「抓圖」的問題。

實行方式
Copy Sub Content:對將被拖曳的SVG圖象使用『cloneNode(true)』如:
  var subSVGObj = SVGObj.cloneNode(true);
  subSVGObj.setAttribute("display","none");
上述程式內容是對目標SVG圖象Copy一份相同的內容至subSVGObj內(記得預設為隱藏),接下來有兩個動作:
  隱藏主SVG內容
  function contentHide(){
    subSVGObj.setAttribute("display","inline");
    SVGObj.setAttribute("display","none");
  }
  回愎顯示主SVG內容
  function contentShow(){
    SVGObj.setAttribute("display","inline");
    subSVGObj.setAttribute("display","none");    
  }
步驟:
當onmousedown產生作用時:

  contentHide( );
  setTimeout("contentShow( )",100);

上述描述即「先隱藏主SVG物件,顯示副SVG物件,0.1秒後再回愎」。