\r
/*アニメーションを開始させるメソッド*/\r
startAnimation: function() {\r
- /*__step関数は最後に書く*/\r
- __step();\r
+ /*$getDocument.step関数は最後に書く*/\r
+ base("$getDocument").step();\r
},\r
\r
/*アニメーションが停止した状態かどうか、停止しているならばtrue*/\r
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
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
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
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
}\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
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
/*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
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
* 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
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
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
}\r
},\r
\r
- /*$animateElement.tocallメソッドを置き換えるためのメソッド\r
+ /*this.$animateElement.tocallメソッドを置き換えるためのメソッド\r
* mpath要素が指定されたときか、path属性のときにのみ使われる*/\r
_tocallForPath: function(advance) {\r
var path = this.path,\r
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
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
}\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