ILOG Elixir

IBM ILOG Elixir:マッシュアップに使える時計ウィジェットを作成する--ステップ1:まずは時計を作る

2009-06-11 08:00:00

 Web 2.0の世界で、iGoogleNetvibesといったマッシュアッププラットフォームがますます人気を集めている。そんな中、Flexのものをそれらとどう統合できるかを考えてみるのは興味深い課題だ。今回作成するウィジェットは、そのもっとも典型的な例の1つである、アナログ時計。iGoogleのウィジェットライブラリで「clock」を検索すると、その検索結果は10ページ以上にも及ぶ。この最初の記事では、IBM ILOG Elixirのゲージ・フレームワークを使ってアナログ時計を作成し、2つめの記事で、Netvibesが提供しているUWA(Universal Widget API)を使い、このウィジェットをマッシュアップ・プラットフォームに統合する。このAPIには、iGoogle、iPhone、Vistaなど多くのマッシュアップ・プラットフォームと互換性を持つという利点がある。

IBM ILOG Elixirゲージ・フレームワークでアナログ時計を作成する

 アナログ時計は、次のような特徴を持つ円形ゲージだと考えることができる。

  • 開始角度が終了角度と一致する
  • 2つの論理スケールを持つ(時間、分、秒)
    • 時間のスケール: 0から12
    • 分および秒のスケール: 0から60
  • 1から12までのラベルのある、分に対応する1つのスケールレンダラを持つ
  • 3つの針を持つ(時間、分、秒)
  • 背景と針をつなぐ部分を持つ

論理スケールを定義する

 最初に定義する第1の論理スケールは分と秒に対応し、こちらがデフォルトスケールになる。2つ目が時間に対応する。

 スケールは次のような形で定義される。

<ilog:scales>
  <ilog:CircularLinearScale id="sixtyScale" startAngle="90" endAngle="90"
    minimum="0" maximum="60" majorTickInterval="5" minorTickInterval="1"/>
  <ilog:CircularLinearScale id="twelveScale" startAngle="90" endAngle="90"
    minimum="0" maximum="12" majorTickInterval="1" minorTickInterval="1"/>
</ilog:scales>

視覚要素を定義する

 この時計は、次の視覚要素から構成される。

  1. 1つの背景(CircleRenderer)
  2. 1つのスケールレンダラ(CircleScaleRenderer)
  3. 3本の針(NeedleRenderer)
  4. 針をつなぐ部分(CircleRenderer)

 時計のスタイルは、各視覚要素のfilters、fill、およびstrokeプロパティを使って定義する。スケールレンダラの小目盛りは分と秒に対応するが、ラベルは時間に対応する。そのため、1から12までの正しいラベルを得られるよう、次のようにラベルを指定する関数を定義する。

private function formatLabel(t:TickItem):String
{
  var v:Number = Number(t.value);
  return String(v==0?12:v/5);
}

針を動かす

 次に、針を動かさなくてはならない。これには、Timerを使って1秒に1回(1000ミリ秒に1回)イベントを呼び出す。

 針の値は、一度進むごとに次のように計算される。

private function init():void{
  timer.addEventListener(TimerEvent.TIMER, timerListener);
  setTime(0, 0, 0);
  timer.start();
}

private function timerListener(e:TimerEvent):void
{
  var currentTime:Date = new Date();
  var h:Number, m:Number, s:Number;
  h = currentTime.hours + (currentTime.minutes * 60 + currentTime.seconds) / 3600;
  m = currentTime.minutes;
  s = currentTime.seconds;
  setTime(h, m, s);
}

private function setTime(h:Number, m:Number, s:Number):void
{
  hourNeedle.value = h;
  minuteNeedle.value = m;
  secondNeedle.value = s;
}

 この単純なアナログ時計の完全なコードは、以下のようになる。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:ilog="http://www.ilog.com/2007/ilog/flex" backgroundColor="0xFFFFFF"
  backgroundGradientColors="[]" layout="absolute"
  creationComplete="init()">
  <mx:Script>
    <![CDATA[
      import mx.effects.easing.*;
      import ilog.gauges.TickItem;

      private var timer:Timer = new Timer(1000);

      private function formatLabel(t:TickItem):String
      {
        var v:Number = Number(t.value);
        return String(v==0?12:v/5);
      }

      private function init():void
      {
        timer.addEventListener(TimerEvent.TIMER, timerListener);
        setTime(0, 0, 0);
        timer.start();
      }

      private function timerListener(e:TimerEvent):void
      {
        var currentTime:Date = new Date();
        var h:Number, m:Number, s:Number;
        h = currentTime.hours + (currentTime.minutes * 60 + currentTime.seconds) / 3600;
        m = currentTime.minutes;
        s = currentTime.seconds;
        setTime(h, m, s);
      }

      private function setTime(h:Number, m:Number, s:Number):void
      {
        hourNeedle.value = h;
        minuteNeedle.value = m;
        secondNeedle.value = s;
      }

    ]]>
  </mx:Script>

  <mx:LinearGradient angle="0" id="needleGradient">

    <mx:GradientEntry color="0xEEEEEE"/>
    <mx:GradientEntry color="0xFFFFFF"/>
    <mx:GradientEntry color="0xEEEEEE" alpha="0.9"/>
    <mx:GradientEntry color="0xFFFFFF"/>
  </mx:LinearGradient>

  <mx:Array id="clockFilters">

    <mx:DropShadowFilter distance="0.8"/>
  </mx:Array>

  <ilog:CircularGauge id="clockg" width="100%" height="100%" backgroundAlpha="0"
    fontWeight="bold" alpha="1">
    <ilog:scales>
      <ilog:CircularLinearScale id="sixtyScale" startAngle="90" endAngle="90"
        minimum="0" maximum="60" majorTickInterval="5" minorTickInterval="1"/>
      <ilog:CircularLinearScale id="twelveScale" startAngle="90" endAngle="90"
        minimum="0" maximum="12" majorTickInterval="1" minorTickInterval="1"/>

    </ilog:scales>
    <ilog:elements>
      <ilog:CircleRenderer radius="50%" id="back" filters="{clockFilters}">
        <ilog:fill>
          <mx:LinearGradient angle="45">
            <mx:GradientEntry color="0xFFFFFF"/>

            <mx:GradientEntry color="0xEEEEEE"/>
          </mx:LinearGradient>
        </ilog:fill>
      </ilog:CircleRenderer>
      <ilog:CircularScaleRenderer radius="48%" filters="{clockFilters}" alpha="0.6"
        color="0xFFFFFF" labelFunction="formatLabel" labelFontSize="18%"
        majorTickWidth="3%" majorTickLength="14%" minorTickWidth="1.5%"
        minorTickLength="7%">
        <ilog:minorTickRenderer>

          <mx:Component>
            <ilog:RectangleTickRenderer>
              <ilog:fill>
                <mx:LinearGradient angle="90">
                  <mx:GradientEntry color="0xDDDDDD" alpha="1"/>
                  <mx:GradientEntry color="0xFFFFFF" alpha="1"/>

                </mx:LinearGradient>
              </ilog:fill>
            </ilog:RectangleTickRenderer>
          </mx:Component>
        </ilog:minorTickRenderer>
        <ilog:majorTickRenderer>

          <mx:Component>
            <ilog:RectangleTickRenderer>
              <ilog:fill>
                <mx:LinearGradient angle="-90">
                  <mx:GradientEntry color="0xDDDDDD" alpha="1"/>
                  <mx:GradientEntry color="0xFFFFFF" alpha="1"/>

                </mx:LinearGradient>
              </ilog:fill>
              <ilog:stroke>
                <mx:Stroke color="0xEEEEEE" alpha="0.5"/>
              </ilog:stroke>
            </ilog:RectangleTickRenderer>

          </mx:Component>
        </ilog:majorTickRenderer>

      </ilog:CircularScaleRenderer>
      <ilog:NeedleRenderer fill="{needleGradient}" id="minuteNeedle" radius="42%"
        baseRadius="{-0.2*hourNeedle.percentRadius*hourNeedle.height/100}"
        pointRadius="100%" filters="{clockFilters}"/>
      <ilog:NeedleRenderer id="hourNeedle" radius="30%"
        baseRadius="{-0.2*hourNeedle.percentRadius*hourNeedle.height/100}"
        filters="{clockFilters}" fill="{needleGradient}" scale="{twelveScale}"
        pointRadius="100%" click="{hourNeedle.invalidateDisplayList()}">
      </ilog:NeedleRenderer>

      <ilog:NeedleRenderer id="secondNeedle" radius="46%" animationDuration="200"
        baseRadius="{-0.2*hourNeedle.percentRadius*hourNeedle.height/100}"
        filters="{clockFilters}" fill="{needleGradient}" pointRadius="100%"
        thickness="1%" easingFunction="{Exponential.easeOut}"/>
      <ilog:CircleRenderer radius="3%" alpha="1" id="cap">
        <ilog:filters>
          <mx:DropShadowFilter distance="1"/>
        </ilog:filters>
        <ilog:fill>

          <mx:LinearGradient angle="45">
            <mx:GradientEntry color="0xCCCCCC"/>
            <mx:GradientEntry color="0xFFFFFF"/>
          </mx:LinearGradient>
        </ilog:fill>
        <ilog:stroke>

          <mx:Stroke color="0xCCCCCC"/>
        </ilog:stroke>
      </ilog:CircleRenderer>
    </ilog:elements>
  </ilog:CircularGauge>
</mx:Application>

 このアプリケーションのFlex Builderプロジェクトは、ここから.zipファイルでダウンロードできる。これを動かすには、IBM ILOG Elixirもダウンロードする必要がある。

 IBM ILOG Elixirについての詳細は、http://www.ilog.co.jp/product/visu/ilogelixir/をご覧ください。

 


原文へ

 

※このエントリは ブロガーにより投稿されたものです。朝日インタラクティブ および ZDNet Japan編集部の見解・意向を示すものではありません。
  • 新着記事
  • 特集
  • ブログ