canvas 周りの I/F を変更しました。

window.uudraw を window.xcanvas に、window.uuboot を window.xboot に変更しました。

uupaa.js / uuCanvas.js コードリード用のエントリです。

I/F をスッキリさせたかった → Silverlight の初期化周りの問題を解決した

Silverlight の初期化処理を非同期から同期処理に書き換えることが出来たので、uuCanvas.js の初期化系の I/F を変更します。

経緯とか、何が問題だったのか とか

uuCanvas.js は元々「excanvas.js の機能不足を何とかしよう」を基点にスタートしたプロジェクトです。

excanvas.js は動的に生成した canvas の利用にちょっとしたコツが必要で document.body.appendChild(document.createElement("canvas")) するだけでは canvas を利用できず、G_vmlCanvasManager.initElement(node) で初期化にする必要があります。また初期化タイミングもユーザが意識する必要があるなど、慣れが必要です。

uuCanvas.js も同様に、 uuCanvas.init(node) で初期化する必要がありましたが、今回はそういうのを無くしてスッキリさせました。

変更前の I/F

uuCanvas.js version 1.0.x では、このような I/F を出しています。

  • uuCanvas.init
    • uuCanvas.init(canvas, vml = false) は、動的に生成された canvas 要素を初期化します。 vml に true を指定した場合は、VMLレンダリングするように初期化を行います。
  • uuCanvas.ready
    • uuCanvas.ready(fn) は レンダリングが可能になったタイミングで fn をコールバックします。
  • uuCanvas.already
    • uuCanvas.already() は ページ上の全ての canvas が使用可能なら true を返します。

このような I/F になっているのは、

  • Silverlight の初期化が非同期なため
  • document.createElement("canvas") で生成した要素は uuCanvas.init で初期化しないと利用できない

という理由からです。

変更後の I/F

このようにしました。

  • uu.canvas(var_args)
    • 初期化済みの(すぐに利用可能な) canvas 要素を返します。uu.canvas("width,300,height,150") とするとサイズ付きで生成します。他の属性やスタイルも生成時に一緒に指定できます。
  • document.createElement("canvas")
  • document.createElement("canvas", 1)
  • uu.canvas.init()
    • ライブラリの遅延ロード(ページをロードしてから2秒後にライブラリをAjaxで読み込むとか)した際に呼び出すと、ページに存在する <canvas> 要素を探し、色々と必要な処理を行います。
  • window.xcanvas = function(uu, CanvasNodeList) { ... 描画処理 ... }
    • グローバルスコープに、xcanvas 関数を定義しておくと canvas が安全に利用可能になったタイミングで、コールバックします(安全にレンダリング可能になるタイミングはブラウザ毎に異なります)
    • 第一引数にライブラリのルート(uu) を 第二引数には canvas のノードリスト(配列)を渡します。

インライン XAML は基本的に不要に

XAML 用のコード(↓)を埋め込む必要はなくなりました。

  <script type="text/xaml" id="xaml"><?xml version="1.0"?>
        <Canvas xmlns="http://schemas.microsoft.com/client/2007"></Canvas></script>

# 埋め込んだままでも問題ありません。

2009-10-29 追記
ライブラリの遅延ロードを行う場合は、従来どおり ページ内に inline XAML を埋め込んでおく必要があります。

<!doctype html><html><head><title>lazyLoad</title>
<!--
<script type="text/javascript" src="../uupaa.js"></script>
 -->
<script type="text/xaml" id="xaml"><?xml version="1.0"?>
  <Canvas xmlns="http://schemas.microsoft.com/client/2007"></Canvas>
</script>
    <script>
      function jsloader() {
        lazyLoad("../uupaa.js", function() {
            drawShape(document.getElementById('canvas'));
            drawShape(document.getElementById('vmlcanvas'));
        });
      }
   :
   :
変更前

uuCanvas.js 1.0.x 用のコード

<!doctype html><html><head>
  <title>Hello HTML5::Canvas world</title>
  <script type="text/xaml" id="xaml"><?xml version="1.0"?>
        <Canvas xmlns="http://schemas.microsoft.com/client/2007"></Canvas></script>
  <script src="../uuCanvas.js"></script>
  <script>
  window.onload = function() {
    uuCanvas.ready(function() {
      var ctx = document.getElementById("canvas").getContext("2d");
         :
    });
  }
  </script>
</head><body>
  <div>
    <canvas id="canvas"></canvas>
  </div>
</body></html>
変更後

uupaa.js 0.7 用のコード

<!doctype html><html><head>
  <title>Hello HTML5::Canvas world</title>
  <script src="../uupaa.js"></script>
  <script>
  function xcanvas(uu, canvas) {
    var ctx = canvas[0].getContext("2d");
         :
  }
  </script>
</head><body>
  <div>
    <canvas></canvas>
  </div>
</body></html>

動的に canvas を生成する

uuCanvas.js 1.0.x 用のコード

<!doctype html><html><head>
  <title>Hello HTML5::Canvas world</title>
  <script type="text/xaml" id="xaml"><?xml version="1.0"?>
        <Canvas xmlns="http://schemas.microsoft.com/client/2007"></Canvas></script>
  <script src="../uuCanvas.js"></script>
  <script>
  window.onload = function() {
    var node1 = document.createElement("canvas"), node2;

    node2 = uuCanvas.init(node1); // 初期化したノードを受け取る(node1 と node2 は別物)

    document.body.appendChild(node2); // node2 を <body> に追加(node1 ではダメ)

    var ctx = canvas.getContext("2d");
         :
  };
  </script>
</head><body></body></html>

uupaa.js 0.7 用のコード

<!doctype html><html><head>
  <title>Hello HTML5::Canvas world</title>
  <script src="../uupaa.js"></script>
  <script>
  function xboot(uu) {
    var node, ctx;

    uu.body(node = uu.canvas()); // <canvas> の生成と、<body> への appendChild

    ctx = node.getContext("2d");
         :
  }
  </script>
</head><body></body></html>

反省会

  • I/F の大幅修正により互換性が無くなりました。
    • uuCanvas.js へのバックポートはしていません。
  • これらの修正と共に、Silverlight モードのレンダリング速度向上と bugfix も行っています。
  • 非同期を同期に書き換えた方法はソースを読んで下さい。
      • uu.canvas.js::_createElement(), uu.canvas.js::initSL(), uu.canvas.js::onPropertyChange(), uu.canvas.sl.js::_drawxaml()