OSDN Git Service

Modify the _tocallForPath method
[sie/sie.git] / org / w3c / dom / smil.js
index 45ed0f7..4af130d 100644 (file)
@@ -47,8 +47,8 @@ base("$frame").mix ( {
   \r
   /*アニメーションを開始させるメソッド*/\r
   startAnimation: function() {\r
-    /*__step関数は最後に書く*/\r
-    __step();\r
+    /*$getDocument.step関数は最後に書く*/\r
+    base("$getDocument").step();\r
   },\r
   \r
   /*アニメーションが停止した状態かどうか、停止しているならばtrue*/\r
@@ -58,6 +58,17 @@ base("$frame").mix ( {
   pauseAnimation: function() {\r
     this.isPaused = true;\r
   },\r
+  \r
+  /*後述のinitializeメソッドで使うオブジェクトリスト*/\r
+  objList: [],\r
+  \r
+  /*オブジェクトの初期化処理*/\r
+  initialize: function() {\r
+    var list = this.objList;\r
+    for (var i=0;i<list.length;++i) {\r
+      list[i].initialize();\r
+    }\r
+  },\r
 \r
   /*setFrame メソッド\r
    * フレーム数を数値num まで進めるか、戻す*/\r
@@ -1284,6 +1295,13 @@ base("$calcMode").up("$attribute").mix( {
      return s;\r
    },\r
    \r
+  /*isKeyErrorメソッド\r
+   * 後述のsetKeyメソッドで使われる。keyTimes属性のエラーをチェックするメソッド\r
+   * 属性値にエラーがあれば、trueを返し、なければ、falseを返す*/\r
+  isKeyError: function(/*number*/ keyLength, /*number*/toLength) {\r
+    return !!(keyLength && (keyLength !== (toLength+1)) );\r
+  },\r
+   \r
    /*setKeyメソッド\r
     * 引数の要素のkeyTimes属性やkeySplines属性を処理するためのメソッド\r
     * 必要な他の属性処理はsetValuesメソッドに任せている*/\r
@@ -1293,6 +1311,7 @@ base("$calcMode").up("$attribute").mix( {
           this.getAttr("from", null),\r
           this.getAttr("to", null),\r
           this.getAttr("by", null) ),\r
+         toLength = to ? to.length : 0,\r
          keyTimes = this.getAttr("keyTimes", null),\r
          keySplines = this.getAttr("keySplines", null),\r
          keys,\r
@@ -1308,13 +1327,22 @@ base("$calcMode").up("$attribute").mix( {
         return null;\r
       }\r
       /*toオブジェクトはtoとfromで一組となっているのでlengthが加算される*/\r
-      if (keys.length && (keys.length !== (to.length+1))) {\r
+      if (this.isKeyError(keys.length, toLength)) {\r
         /*keyTimes属性とvalues属性のリストの個数が合致しない場合、アニメーションの効果がない\r
          * 仕様を参照 SMIL Animation 3.2.3. Animation function calculation modes\r
          * http://www.w3.org/TR/smil-animation/#AnimFuncCalcMode*/\r
+         \r
+        /*ただし、animateMotion要素においては、keyPoints属性が\r
+         * values属性のリストよりも優先されるため、\r
+         * keyPoints属性があるときは、アニメーションの効果がある\r
+         * \r
+         * >Regarding determining the points which correspond to the ‘keyTimes’ attributes, the ‘keyPoints’ attribute overrides ‘path’, which overrides ‘values’\r
+         * \r
+         * http://www.w3.org/TR/SVG11/animate.html#AnimateMotionElement\r
+         */\r
         return null;\r
       }\r
-      for (var i=0;i<to.length;++i) {\r
+      for (var i=0;i<toLength;++i) {\r
         to[i].keyTime = keys[i+1] - keys[i];\r
         if (splines) {\r
           toiKeySplines = this.$from.numList.call( {\r
@@ -1325,8 +1353,8 @@ base("$calcMode").up("$attribute").mix( {
         }\r
       }\r
     } else if (!isDiscrete && to) {\r
-      var per = 1 / to.length;\r
-      for (var i=0;i<to.length;++i) {\r
+      var per = 1 / toLength;\r
+      for (var i=0;i<toLength;++i) {\r
         to[i].keyTime = per;\r
         if (splines) {\r
           toiKeySplines = this.$from.numList.call( {\r
@@ -1345,20 +1373,20 @@ base("$calcMode").up("$attribute").mix( {
         if (keys.length && (keys[0] !== 0)) {\r
           return null;\r
         }\r
-        if (keys.length && (keys.length !== (to.length+1))) {\r
+        if (this.isKeyError(keys.length, toLength)) {\r
           return null;\r
         }\r
-        for (var i=0;i<to.length;++i) {\r
+        for (var i=0;i<toLength;++i) {\r
           to[i].keyTime = keys[i+1] - keys[i];\r
         }\r
       } else {\r
-        var per = 1 / (to.length+1);\r
-        for (var i=0;i<to.length;++i) {\r
+        var per = 1 / (toLength+1);\r
+        for (var i=0;i<toLength;++i) {\r
           to[i].keyTime = per;\r
         }\r
       }\r
       /*toオブジェクトが足らないので、一つ追加しておく*/\r
-      to.push( to[to.length-1].up().mix( function(){\r
+      to.push( to[toLength-1].up().mix( function(){\r
           if (!keys) {\r
             return;\r
           }\r
@@ -1390,6 +1418,34 @@ base("$calcMode").up("$attribute").mix( {
   /*to属性の値、文字列*/\r
   to: "",\r
   \r
+  \r
+  /*後述のinitializeメソッドで使う要素リスト\r
+   * getElementsByTagNameNSメソッドの返り値をArray化したことを想定*/\r
+  elementList: [],\r
+  \r
+  /*何番目からelementListを処理しているかの数値*/\r
+  numberOfElemList: 0,\r
+  \r
+  /*initialize メソッド\r
+   * 要素リストを初期化させる\r
+   * 初期化処理を分散させるために使う*/\r
+  initialize: function() {\r
+    var eles = this.elementList;\r
+    if (!eles || !eles.length) {\r
+      return;\r
+    }\r
+    var length = this.numberOfElemList+50;\r
+    for (var i=length-50; i<length; ++i) {\r
+      if (eles.length <= i) {\r
+        this.elementList = null;\r
+        return;\r
+      }\r
+      this.up().init(eles[i]);\r
+    }\r
+    this.numberOfElemList += 50;\r
+    eles = length = void 0;\r
+  },\r
+   \r
   /*initメソッドで使われるアニメーション関数*/\r
   _setFrame: function ($list) {\r
     this.setAttribute(this.to);\r
@@ -1761,7 +1817,9 @@ base("$calcMode").up("$attribute").mix( {
     to = this.setKey(ele);\r
   }\r
   if (to) {\r
-    this.funcs = to.map( function(x) {\r
+    var aa = new Array(to.length);\r
+    for (var i=0;i<to.length;++i) {\r
+      var x = to[i];\r
       x.to.string = toRGB(x.to.string);\r
       x.to.from.string = toRGB(x.to.from.string);\r
       var s = x.call();\r
@@ -1770,9 +1828,9 @@ base("$calcMode").up("$attribute").mix( {
        * endKeyTimeプロパティは区間のエンド地点*/\r
       s.startKeyTime = keyTime;\r
       keyTime = s.endKeyTime = keyTime + x.keyTime;\r
-      return s;\r
-    } )\r
-     .filter( function(s) {\r
+      aa[i] = s;\r
+    }\r
+    this.funcs = aa.filter( function(s) {\r
        if (!this.timeline.isResolved) {\r
          /*begin属性などにイベントを設定していた(未解決の)場合、後のs(0.1)がうまく作動せず、\r
           * 例外を出してしまうため、ここで返しておく*/\r
@@ -1785,7 +1843,7 @@ base("$calcMode").up("$attribute").mix( {
     this.setAdd(ele, to);\r
     this.setAccum(ele, to);\r
   }\r
-  keywords = toRGB = isColor = void 0;\r
+  keyTime = keywords = toRGB = isColor = void 0;\r
 } )\r
 /*$animateTranformElementオブジェクト\r
  * animateTransform要素に関連するオブジェクト*/\r
@@ -1935,12 +1993,12 @@ base("$calcMode").up("$attribute").mix( {
     mode: "paced",\r
         \r
     /*hasAttrValuesメソッドのオーバライド\r
-     * path属性に対応させるため*/\r
+     * pathå±\9eæ\80§ã\81ªã\81©ã\81«å¯¾å¿\9cã\81\95ã\81\9bã\82\8bã\81\9fã\82\81*/\r
     hasAttrValues: function () {\r
       if (this.$attribute.hasAttrValues.call(this)) {\r
         return true;\r
       } else {\r
-        return (this._ele.hasAttribute("path")\r
+        return (this._ele.hasAttribute("keyPoints") || this._ele.hasAttribute("path")\r
                  || this._ele.getElementsByTagNameNS(this.path.namespaceURI, "mpath").length);\r
       }\r
     },\r
@@ -1994,7 +2052,7 @@ base("$calcMode").up("$attribute").mix( {
       }\r
     },\r
     \r
-    /*$animateElement.tocallメソッドを置き換えるためのメソッド\r
+    /*this.$animateElement.tocallメソッドを置き換えるためのメソッド\r
      * mpath要素が指定されたときか、path属性のときにのみ使われる*/\r
     _tocallForPath: function(advance) {\r
       var path = this.path,\r
@@ -2012,7 +2070,26 @@ base("$calcMode").up("$attribute").mix( {
         rotate = +this.rotate;\r
       }\r
       return point.x+ "," +point.y + this.getRotate(path, advanceLength, rotate);\r
-    }\r
+    },\r
+    \r
+    /*setValuesメソッドのオーバライド*/\r
+    setValues: function() {\r
+      var keyPoints = this.getAttr("keyPoints", null),\r
+          /*$animateElementプロパティは下記のinitメソッドで上書きされているため、\r
+           * $animateElementを別方法で呼び出す必要がある*/\r
+          superSetValues = this.$animateElement.$animateElement.setValues;\r
+      if (keyPoints) {\r
+        return superSetValues.call(this, keyPoints, null, null, null);\r
+      } else {\r
+        return superSetValues.apply(this, arguments);\r
+      }\r
+    },\r
+    \r
+    /*isKeyErrorメソッドのオーバライド\r
+     *keyPoints属性があれば、処理するようにする*/\r
+    isKeyError: function() {\r
+      return !!this.getAttr("keyPoints", false) || this.$animateElement.isKeyError.apply(this, arguments);\r
+    },\r
   } )\r
   .on("init", function (ele) {\r
     if (!ele || !ele.parentNode) {\r
@@ -2025,6 +2102,12 @@ base("$calcMode").up("$attribute").mix( {
     this.isSum = true;\r
     this.mode = this.getAttr("mode", "paced");\r
     this.rotate = this.getAttr("rotate", "0");\r
+    if (ele.hasAttributeNS(null, "keyPoints") && !ele.hasAttributeNS(null, "path")) {\r
+      /*keyPoints属性がある場合は、path属性に指定がなければ、\r
+       * values属性などの値をpath属性に書いておく*/\r
+       var values = this.getAttr( "values", this.getAttr("from", "")+","+this.getAttr("to", "") );\r
+       ele.setAttributeNS( null, "path", "M " +values.replace(/;/g, " ") );\r
+    }\r
     this.path = this.path.cloneNode(true);\r
     var mpath = ele.getElementsByTagNameNS(this.path.namespaceURI, "mpath");\r
     /*$animateは後で、プロパティを書き換えるために使う。tocallメソッドも参照*/\r
@@ -2041,93 +2124,101 @@ base("$calcMode").up("$attribute").mix( {
     }\r
   } );\r
 \r
-function getDocument() \r
-{\r
-  var svg = document.getElementsByTagName("object"),\r
-      svgns = "http://www.w3.org/2000/svg";\r
-  if (svg) {\r
-    for (var i=0;i<svg.length;++i) {\r
-      getElement( svg[i].getSVGDocument() );\r
+base("$getDocument").mix ( function() {\r
+\r
+  function getDocument() \r
+  {\r
+    var svg = document.getElementsByTagName("object"),\r
+        svgns = "http://www.w3.org/2000/svg";\r
+    if (svg) {\r
+      for (var i=0;i<svg.length;++i) {\r
+        getElement( svg[i].getSVGDocument() );\r
+      }\r
     }\r
+    /*SVG文書から呼び出されたときも処理する*/\r
+    getElement(document);\r
+    /*idはアニメの中止ハンドル*/\r
+    var id = __step(),\r
+        idstop = function() {\r
+          /*アニメーションを中止する関数*/\r
+          window.cancelAnimationFrame && cancelAnimationFrame(id);\r
+        };\r
+    base("$frame").on("pauseAnimation", idstop);\r
+    window.addEventListener("unload", idstop);\r
+    \r
+    /*文書からアニメーション関連要素を取り出して、オブジェクトを初期化*/\r
+    function getElement (svgDoc) {\r
+        var $set = base("$calcMode").$attribute.$setElement,\r
+            $animate = $set.$animateElement,\r
+            frame = base("$frame");\r
+        init($set, "set");\r
+        init($animate, "animate");\r
+        init($animate.up(), "animateColor");\r
+        init($animate.$animateTransformElement, "animateTransform");\r
+        init($animate.$animateTransformElement.$motionElement, "animateMotion");\r
+          /*リンクのハッシュ読み取りで、ハイパーリンクのイベント処理\r
+         * たとえば、a要素のxlink:href="#hoge"で、<animate id="hoge"のとき、\r
+         * animate要素がハイパーリンク作動と同時に動くようになる\r
+         * \r
+         * ただし、SMIL アニメーションの仕様では、\r
+         * animate要素の開始時刻まで、時を進める操作をするだけ*/\r
+         svgDoc.defaultView.addEventListener("hashchange", function() {\r
+             var hash = svgDoc.defaultView.location.hash.slice(1);\r
+             svgDoc.getElementById(hash).beginElement();\r
+           });\r
+        function init (obj, name) {\r
+          /*あとでframe.initializeメソッドで呼び出すために準備しておく*/\r
+          var elist = svgDoc.getElementsByTagNameNS(svgns, name);\r
+          obj.numberOfElemList = 0;\r
+          if (elist.length > 0) {\r
+            obj.elementList = elist;\r
+            frame.objList.push(obj);\r
+          }\r
+          elist = obj = void 0;\r
+        };\r
+    };\r
   }\r
-  /*SVG文書から呼び出されたときも処理する*/\r
-  getElement(document);\r
-  /*idはアニメの中止ハンドル*/\r
-  var id = __step(),\r
-      idstop = function() {\r
-        /*アニメーションを中止する関数*/\r
-        window.cancelAnimationRequest && cancelAnimationRequest(id);\r
-      };\r
-  base("$frame").on("pauseAnimation", idstop);\r
-  window.addEventListener("unload", idstop);\r
   \r
-  /*文書からアニメーション関連要素を取り出して、オブジェクトを初期化*/\r
-  function getElement (svgDoc) {\r
-      var $set = base("$calcMode").$attribute.$setElement,\r
-          $animate = $set.$animateElement;\r
-      init($set, "set");\r
-      init($animate, "animate");\r
-      init($animate, "animateColor");\r
-      init($animate.$animateTransformElement, "animateTransform");\r
-      init($animate.$animateTransformElement.$motionElement, "animateMotion");\r
-        /*リンクのハッシュ読み取りで、ハイパーリンクのイベント処理\r
-       * たとえば、a要素のxlink:href="#hoge"で、<animate id="hoge"のとき、\r
-       * animate要素がハイパーリンク作動と同時に動くようになる\r
-       * \r
-       * ただし、SMIL アニメーションの仕様では、\r
-       * animate要素の開始時刻まで、時を進める操作をするだけ*/\r
-       svgDoc.defaultView.addEventListener("hashchange", function() {\r
-           var hash = svgDoc.defaultView.location.hash.slice(1);\r
-           svgDoc.getElementById(hash).beginElement();\r
-         });\r
-\r
-      function init (obj, name) {\r
-        var eles = svgDoc.getElementsByTagNameNS(svgns, name)\r
-        for (var i=0;i<eles.length;++i) {\r
-          obj.up().init(eles.item(i));\r
-        }\r
-        eles = obj = void 0;\r
-      };\r
-  };\r
-}\r
+  window.addEventListener && window.addEventListener("load", getDocument);\r
 \r
-window.addEventListener && window.addEventListener("load", getDocument);\r
-\r
-function __step() {\r
-/*EdgeはhasFeatureメソッドでtrueを返す*/\r
-if (!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Animation", "1.1")\r
-    || window.navigator.userAgent.toLowerCase().indexOf("edge")) {\r
-  if (window.requestAnimationFrame && requestAnimationFrame) {\r
-    /*IE11などSMILアニメーションに対応していないブラウザ用*/\r
-    /*cancelはアニメーションの中止ハンドル*/\r
-    var cancel = {\r
-       handle: null\r
-      };\r
-    (function(frame) {\r
-      var $frame = base("$frame"),\r
-          _cancel = cancel; /*cancelのエイリアス*/\r
-      _cancel.handle = requestAnimationFrame(step);\r
-      function step() {\r
-        if (!$frame.isPaused) {\r
-          frame++;\r
-          try {\r
-            $frame.setFrame(frame);\r
-          } catch(e) {\r
-          }\r
+  this.step = __step;\r
+  function __step() {\r
+    /*EdgeはhasFeatureメソッドでtrueを返す*/\r
+    if (!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Animation", "1.1")\r
+        || (window.navigator.userAgent.toLowerCase().indexOf("edge") > 0)) {\r
+      if (window.requestAnimationFrame && requestAnimationFrame) {\r
+        /*IE11やEdgeなどSMILアニメーションに対応していないブラウザ用*/\r
+        /*cancelはアニメーションの中止ハンドル*/\r
+        var cancel = {\r
+           handle: null\r
+          };\r
+        (function(frame) {\r
+          var _cancel = cancel; /*cancelのエイリアス*/\r
+          var step = function () {\r
+            if (!this.isPaused) {\r
+              frame++;\r
+              try {\r
+                this.initialize();\r
+                this.setFrame(frame);\r
+              } catch(e) {\r
+              }\r
+              _cancel.handle = requestAnimationFrame(step);\r
+            }\r
+          }.bind(base("$frame"));\r
           _cancel.handle = requestAnimationFrame(step);\r
-        }\r
-      };\r
-    })(-1);\r
-    return cancel;\r
-  } else {\r
-    setInterval( (function(frame) {\r
-      var $f = base("$frame");\r
-      return function () {\r
-        frame++;\r
-        $f.setFrame(frame);\r
-      };\r
-    })(-1), 1 );\r
+        })(-1);\r
+        return cancel;\r
+      } else {\r
+        setInterval( (function(frame) {\r
+          var $f = base("$frame");\r
+          return function () {\r
+            frame++;\r
+            $f.initialize();\r
+            $f.setFrame(frame);\r
+          };\r
+        })(-1), 1 );\r
+      }\r
+    }\r
   }\r
-}\r
-}\r
+} );\r
 //#endif // _SMIL_IDL_\r