XAML: デザインの座標変換(基本のみ)
XAMLの座標変換の基本についてまとめる。まとめる内容は以下のうちで、平行性を保った変換(アフィン変換という)のみとする。 アフィン変換ではない、図形の平行性を維持しない(ぐちゃぐちゃに変形できる)ような座標変換(テーパー変換という)は扱わない。
平行移動
図形を平行移動させる。使いどころは、sin波やcos波など波形を扱う場合で、位相差による差分等を比較したいときや、どのような変化をするのかアニメーションで見たいとき。
使うのは「RenderTransform」の「TranslateTransform」。 「X」と「Y」というプロパティを持っており、値を設定して正の方向、負の方向に移動させられる。
今回見せる例はもっと簡単な影付き文字など。 X方向、Y方向に微妙にずらして浮き上がっているように見せたり、へこんでいるように見せたり、影がついているように見える。
xamlコード(Window部分は省略)
<Window.Resources> <Style TargetType="TextBlock"> <Setter Property="FontFamily" Value="Times New Roman" /> <Setter Property="FontSize" Value="102" /> <Setter Property="HorizontalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" /> </Style> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="*" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <TextBlock Text="EMBOSS" Grid.Row="0"/> <TextBlock Text="EMBOSS" Grid.Row="0" Foreground="White"> <TextBlock.RenderTransform> <TranslateTransform X="-2" Y="-2"/> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="ENGRAVE" Grid.Row="1"/> <TextBlock Text="ENGRAVE" Grid.Row="1" Foreground="White"> <TextBlock.RenderTransform> <TranslateTransform X="2" Y="2"/> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="Drop Shadow" Grid.Row="2" Foreground="Gray"> <TextBlock.RenderTransform> <TranslateTransform X="5" Y="5"/> </TextBlock.RenderTransform> </TextBlock> <TextBlock Text="Drop Shadow" Grid.Row="2"/> </Grid>
拡大・縮小
図形を拡大・縮小する。これが最も使うかもしれないやつ。画像を拡大・縮小もするだろうし、平行移動でも扱った波形も拡大したいときがあるだろう。
使うのは「RenderTransform」の「ScaleTransform」。 「ScaleX」と「ScaleY」というプロパティを持っており、X方向、Y方向別々に拡大・縮小できる。
拡大・縮小はイベントやアニメーションとの組み合わせになるため、参考画像はなし。 XAMLコードだけ載せる。
先に書いてしまうと、座標変換はもうだいたいこの形になる。
<TextBlock Text="Sample"> <TextBlock.RenderTransform> <ScaleTransform ScaleX="2"/> </TextBlock.RenderTransform> </TextBlock>
傾斜
図形を傾かせる。そのまんまである。使いどきは、任意に図形を傾かせるという機能が必要なツール。絵を描くツールがその代表と考えられる。
使うのは「RenderTransform」の「SkewTransform」。 「AngleX」と「AngleY」というプロパティを持ち、X方向、Y方向に傾けられる。
サンプルは影を傾かせた文字。平行移動も混じっているが、結局この複数の変換を実施するのも後々まとめる。
xamlコードはこんな感じ。RenderTransformOriginは軸中心をいじくるもの。次の回転でまとめる。
<Window.Resources> <Style TargetType="TextBlock"> <Setter Property="Text" Value="quirky" /> <Setter Property="FontFamily" Value="Times New Roman" /> <Setter Property="FontSize" Value="100" /> <Setter Property="HorizontalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" /> </Style> </Window.Resources> <Grid> <TextBlock Foreground="Gray" RenderTransformOrigin="0 1"> <TextBlock.RenderTransform> <!-- compositetransform なんてあるらしい。複数変換をまとめたもの。 --> <TransformGroup> <ScaleTransform ScaleY="1.5"/> <SkewTransform AngleX="-60"/> </TransformGroup> </TextBlock.RenderTransform> </TextBlock> <TextBlock/> </Grid>
回転
図形を回転させる。言ってしまえば、座標に回転行列をかけるもの。これまで説明してきたやつも、すべて行列演算にまとめられる(次章でまとめる)。 実際に使うときは、傾斜と同様に絵を描くツールだろうか。ほかにもありそうだが、自身の経験が偏っているのか思いつかない。
使うのは「RenderTransform」の「RotateTransform」。 「Angle」プロパティを持っており、角度を調整する。
サンプル画像とるのも面倒だったので(おい)xamlコードだけ載せる。
<TextBlock Text="Rotate Text"> <TextBlock.RenderTransform> <RotateTransform Angle="60"/> </TextBlock.RenderTransform> </TextBlock>
実は上記のコードだと回転軸が中心じゃなかったりする。これは、既定の回転軸が(0, 0)であり、この座標は図形の左上を指しているからである。
これを変更するには「RenderTransformOrigin」で回転軸を変更する必要がある。回転軸を中心にずらしたxamlコードは下記のとおり。
<TextBlock Text="Rotate Text" RenderTransformOrigin="0.5 0.5"> <TextBlock.RenderTransform> <RotateTransform Angle="60"/> </TextBlock.RenderTransform> </TextBlock>
座標変換のまとめ
座標変換の基本をまとめた。最後の回転で少し触れたが、これらすべての変換は一つの行列演算で表せる。 元の座標を とし、変換後の座標を とする。
これを解くと下記のとおり。
や は見てのとおり係数である。 拡大、縮小、傾斜、回転すべてこれである。 回転になると といった回転角となる(Aは角度、ラジアン)。 そして、 や が平行移動である。
に対しては係数がない。というか、ないのが普通になるはずだ。 主な理由は「一般的に考えて、回転や拡大の係数が平行移動に係ってほしくない」というもの。
なんでこんな行列演算をまとめたかというと、XAMLでこれをサクッと書けるため。 「RenderTransform」さんに上記で示した係数を渡してやると勝手にやってくれるのだ・・・。
「RenderTransform = ""」
この形式で書いてやればいい(各値は空白区切り)。
xamlコードは下記のとおり。
<Window.Resources> <Style TargetType="TextBlock"> <Setter Property="FontSize" Value="24" /> <Setter Property="RenderTransformOrigin" Value="0 0.5" /> </Style> </Window.Resources> <Grid> <Canvas HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBlock Text=" RenderTransform='1 0 0 1 0 0'" RenderTransform="1 0 0 1 0 0"/> <TextBlock Text=" RenderTransform='.7 .7 -.7 .7 0 0'" RenderTransform=".7 .7 -.7 .7 0 0"/> <TextBlock Text=" RenderTransform='0 1 -1 0 0 0'" RenderTransform="0 1 -1 0 0 0"/> <TextBlock Text=" RenderTransform='-.7 .7 -.7 -.7 0 0'" RenderTransform="-.7 .7 -.7 -.7 0 0"/> <TextBlock Text=" RenderTransform='-1 0 0 -1 0 0'" RenderTransform="-1 0 0 -1 0 0"/> <TextBlock Text=" RenderTransform='-.7 -.7 .7 -.7 0 0'" RenderTransform="-.7 -.7 .7 -.7 0 0"/> <TextBlock Text=" RenderTransform='0 -1 1 0 0 0'" RenderTransform="0 -1 1 0 0 0"/> <TextBlock Text=" RenderTransform='.7 -.7 .7 .7 0 0'" RenderTransform=".7 -.7 .7 .7 0 0"/> </Canvas> </Grid>
座標変換の組み合わせとアニメーション
最後に、これら座標変換を組み合わせた「TransformGroup」とアニメーションを使った例をまとめる。
一つの図形に複数の変換を実施したい場合は「TransformGroup」でまとめてやるだけだ。 そして、各変換値を「DoubleAnimation」でごりごり動かす。
ちょっとレートが低くてカクカクだが、こんな感じだ。
xamlコードは以下のとおり。
<Grid> <Polygon Points="40 0, 60 0, 53 47, 100 40, 100 60, 53 53, 60 100, 40 100, 47 53, 0 60, 0 40, 47 47" Fill="SteelBlue" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5 0.5"> <Polygon.RenderTransform> <TransformGroup> <!-- ここの回転軸はプロペラの中心(画面中央) --> <RotateTransform x:Name="rotate1"/> <!-- ここでプロペラが移動する。なお、プロペラは移動するが、回転軸は変わらず画面中央 --> <TranslateTransform X="300"/> <!-- 回転軸は初期位置(画面中央)なので、この回転は大きな円軌道となる。 --> <RotateTransform x:Name="rotate2"/> </TransformGroup> </Polygon.RenderTransform> </Polygon> </Grid> <Window.Triggers> <EventTrigger RoutedEvent="MouseEnter"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="rotate1" Storyboard.TargetProperty="Angle" From="0" To="360" Duration="0:0:0.5" RepeatBehavior="Forever"/> <DoubleAnimation Storyboard.TargetName="rotate2" Storyboard.TargetProperty="Angle" From="0" To="360" Duration="0:0:6" RepeatBehavior="Forever"/> </Storyboard> </BeginStoryboard> </EventTrigger> </Window.Triggers>