gallery3d: Add new widget
[platform/framework/web/web-ui-fw.git] / src / js / widgets / components / motionpath.js
1 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);\r
2 //>>description: Tizen motion path component for gallery3d\r
3 //>>label: Motion path\r
4 //>>group: Tizen:Widgets:Components\r
5 \r
6 define( [ ], function ( ) {\r
7 //>>excludeEnd("jqmBuildExclude");\r
8 \r
9 /* ***************************************************************************\r
10  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.\r
11  *\r
12  * Permission is hereby granted, free of charge, to any person obtaining a\r
13  * copy of this software and associated documentation files (the "Software"),\r
14  * to deal in the Software without restriction, including without limitation\r
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
16  * and/or sell copies of the Software, and to permit persons to whom the\r
17  * Software is furnished to do so, subject to the following conditions:\r
18  *\r
19  * The above copyright notice and this permission notice shall be included in\r
20  * all copies or substantial portions of the Software.\r
21  *\r
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
25  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\r
28  * DEALINGS IN THE SOFTWARE.\r
29  * ***************************************************************************\r
30  *\r
31  * Authors: Hyunsook Park <hyunsook.park@samsung.com>\r
32  *                      Wonseop Kim <wonseop.kim@samsung.com>\r
33 */\r
34 \r
35 ( function ( $, window, undefined ) {\r
36         var HALF_PI = Math.PI / 2,\r
37                 DEFAULT_STEP = 0.001,\r
38                 MotionPath = {},\r
39                 vec3 = window.vec3,\r
40                 arcLength2d = function ( p0, p1 ) {\r
41                         var d = [ p1[0] - p0[0], p1[1] - p0[1] ],\r
42                                 value = Math.sqrt( d[0] * d[0] + d[1] * d[1] );\r
43                         return value;\r
44                 },\r
45                 arcLength3d = function ( p0, p1 ) {\r
46                         var d = [ p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2] ],\r
47                                 value = Math.sqrt( d[0] * d[0] + d[1] * d[1] + d[2] * d[2] );\r
48                         return value;\r
49                 };\r
50 \r
51         MotionPath.base = function () {};\r
52         MotionPath.base.prototype = {\r
53                 points: [],\r
54                 step: DEFAULT_STEP,\r
55                 length: 0,\r
56                 levels: [],\r
57                 init: function ( data ) {},\r
58                 calculateLevel: function ( maxLevel ) {},\r
59                 calculateTotalLength: function () {},\r
60                 getPosition: function ( percent ) {},\r
61                 getPercent: function ( start, interval ) {},\r
62                 getAngle: function ( percent ) {}\r
63         };\r
64 \r
65         MotionPath.bezier2d = function () {};\r
66         MotionPath.bezier2d.prototype = $.extend( true, {}, MotionPath.base.prototype, {\r
67                 init: function ( data ) {\r
68                         this.points = data.points;\r
69                         this.step = data.step || DEFAULT_STEP;\r
70                         this.length = this.calculateTotalLength();\r
71                         this.levels = this.calculateLevel( data.maxLevel ) || [];\r
72                 },\r
73 \r
74                 calculateLevel: function ( maxLevel ) {\r
75                         var totalLength = this.length,\r
76                                 interval = totalLength / maxLevel,\r
77                                 levels = [],\r
78                                 i;\r
79 \r
80                         if ( !maxLevel ) {\r
81                                 return null;\r
82                         }\r
83 \r
84                         for ( i = 0; i < maxLevel; i += 1 ) {\r
85                                 levels[maxLevel - i] = this.getPercent( 0, interval * i );\r
86                         }\r
87 \r
88                         return levels;\r
89                 },\r
90 \r
91                 calculateTotalLength: function () {\r
92                         var step = this.step,\r
93                                 current = this.getPosition( 0 ),\r
94                                 last = current,\r
95                                 length = 0,\r
96                                 percent;\r
97                         for ( percent = step; percent <= 1; percent += step ) {\r
98                                 current = this.getPosition( percent );\r
99                                 length += arcLength2d( last, current );\r
100                                 last = current;\r
101                         }\r
102                         return length;\r
103                 },\r
104 \r
105                 getPosition: function ( percent ) {\r
106                         var points = this.points,\r
107                                 getValue = function ( p1, c1, c2, p2, t ) {\r
108                                         return Math.pow(1 - t, 3) * p1 +\r
109                                                 3 * t * Math.pow( 1 - t, 2 ) * c1 +\r
110                                                 3 * Math.pow( t, 2 ) * ( 1 - t ) * c2 +\r
111                                                 Math.pow( t, 3 ) * p2;\r
112                                 },\r
113                                 result = [\r
114                                         getValue( points[0][0], points[1][0], points[2][0], points[3][0], percent ),\r
115                                         getValue( points[0][1], points[1][1], points[2][1], points[3][1], percent )\r
116                                 ];\r
117                         return result;\r
118                 },\r
119 \r
120                 getPercent: function ( start, interval ) {\r
121                         var step = this.step,\r
122                                 current = this.getPosition( start = start || 0 ),\r
123                                 last = current,\r
124                                 targetLength = start + interval,\r
125                                 length = 0,\r
126                                 percent;\r
127 \r
128                         for ( percent = start + step; percent <= 1; percent += step ) {\r
129                                 current = this.getPosition( percent );\r
130                                 length += arcLength2d( last, current );\r
131                                 if ( length >= targetLength ) {\r
132                                         return percent;\r
133                                 }\r
134                                 last = current;\r
135                         }\r
136                         return 1;\r
137                 },\r
138 \r
139                 getAngle: function ( percent ) {\r
140                         var points = this.points,\r
141                                 getTangent = function ( p1, c1, c2, p2, t ) {\r
142                                         return 3 * t * t * ( -p1 + 3 * c1 - 3 * c2 + p2 ) + 6 * t * ( p1 - 2 * c1 + c2 ) + 3 * ( -p1 + c1 );\r
143                                 },\r
144                                 tx = getTangent( points[0][0], points[1][0], points[2][0], points[3][0], percent ),\r
145                                 ty = getTangent( points[0][1], points[1][1], points[2][1], points[3][1], percent );\r
146                         return Math.atan2( tx, ty ) - HALF_PI;\r
147                 }\r
148 \r
149         } );\r
150 \r
151         // clamped cubic B-spline curve\r
152         // http://web.mit.edu/hyperbook/Patrikalakis-Maekawa-Cho/node17.html\r
153         // http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/B-spline/bspline-curve-coef.html\r
154         MotionPath.bspline = function () {};\r
155         MotionPath.bspline.prototype = $.extend( true, {}, MotionPath.base.prototype, {\r
156                 _degree: 3,\r
157                 _numberOfControls : 0,\r
158                 _knotVectors: [],\r
159                 _numberOfKnots: 0,\r
160 \r
161                 init: function ( data ) {\r
162                         this.points = data.points;\r
163                         this.step = data.step || DEFAULT_STEP;\r
164                         this._numberOfPoints = this.points.length - 1;\r
165                         this._numberOfKnots = this._numberOfPoints + this._degree + 1;\r
166 \r
167                         var deltaKnot = 1 / ( this._numberOfKnots - ( 2 * this._degree ) ),\r
168                                 v = deltaKnot,\r
169                                 i = 0;\r
170 \r
171                         while ( i <= this._numberOfKnots ) {\r
172                                 if ( i <= this._degree ) {\r
173                                         this._knotVectors.push( 0 );\r
174                                 } else if ( i < this._numberOfKnots - this._degree + 1 ) {\r
175                                         this._knotVectors.push( v );\r
176                                         v += deltaKnot;\r
177                                 } else {\r
178                                         this._knotVectors.push( 1 );\r
179                                 }\r
180                                 i += 1;\r
181                         }\r
182 \r
183                         this.length = this.calculateTotalLength();\r
184                         this.levels = this.calculateLevel( data.maxLevel ) || [];\r
185                 },\r
186 \r
187                 _Np: function ( percent, i, degree ) {\r
188                         var knots = this._knotVectors,\r
189                                 A = 0,\r
190                                 B = 0,\r
191                                 denominator = 0,\r
192                                 N0 = function ( percent, i ) {\r
193                                         return ( ( knots[i] <= percent && percent < knots[i + 1] ) ? 1 : 0 );\r
194                                 };\r
195 \r
196                         if ( degree === 1 ) {\r
197                                 A = N0( percent, i );\r
198                                 B = N0( percent, i + 1 );\r
199                         } else {\r
200                                 A = this._Np( percent, i, degree - 1 );\r
201                                 B = this._Np( percent, i + 1, degree - 1 );\r
202                         }\r
203 \r
204                         denominator = knots[i + degree] - knots[i];\r
205                         A *= ( denominator !== 0 ) ? ( ( percent - knots[i] ) / denominator ) : 0;\r
206                         denominator = knots[i + degree + 1] - knots[i + 1];\r
207                         B *= ( denominator !== 0 ) ? ( ( knots[i + degree + 1] - percent ) / denominator ) : 0;\r
208 \r
209                         return A + B;\r
210                 },\r
211 \r
212                 calculateLevel: function ( maxLevel ) {\r
213                         var totalLength = this.length,\r
214                                 interval = totalLength / maxLevel,\r
215                                 levels = [],\r
216                                 i;\r
217 \r
218                         if ( !maxLevel ) {\r
219                                 return null;\r
220                         }\r
221 \r
222                         for ( i = 0; i < maxLevel; i += 1 ) {\r
223                                 levels[maxLevel - i] = this.getPercent( 0, interval * i );\r
224                         }\r
225                         return levels;\r
226                 },\r
227 \r
228                 calculateTotalLength: function () {\r
229                         var step = this.step,\r
230                                 current = this.getPosition( 0 ),\r
231                                 last = current,\r
232                                 length = 0,\r
233                                 percent;\r
234                         for ( percent = step; percent <= 1; percent += step ) {\r
235                                 current = this.getPosition( percent );\r
236                                 length += arcLength3d( last, current );\r
237                                 last = current;\r
238                         }\r
239                         return length;\r
240                 },\r
241 \r
242                 getPosition: function ( percent ) {\r
243                         var result = [], i, j, sum;\r
244                         percent = percent.toFixed( 4 );\r
245                         for ( j = 0; j < 3; j += 1 ) {\r
246                                 sum = 0;\r
247                                 for ( i = 0; i <= this._numberOfPoints; i += 1 ) {\r
248                                         sum += this.points[i][j] * this._Np( percent, i, this._degree );\r
249                                 }\r
250                                 result[j] = sum;\r
251                         }\r
252 \r
253                         return result;\r
254                 },\r
255 \r
256                 getPercent: function ( start, interval ) {\r
257                         var step = this.step,\r
258                                 current = this.getPosition( start = start || 0 ),\r
259                                 last = current,\r
260                                 targetLength = start + interval,\r
261                                 length = 0,\r
262                                 percent;\r
263 \r
264                         for ( percent = start + step; percent <= 1; percent += step ) {\r
265                                 current = this.getPosition( percent );\r
266                                 length += arcLength3d( last, current );\r
267                                 if ( length >= targetLength ) {\r
268                                         return percent;\r
269                                 }\r
270                                 last = current;\r
271                         }\r
272                         return 1;\r
273                 },\r
274 \r
275                 getAngle: function ( percent ) {\r
276                         var prev = this.getPosition( percent ),\r
277                                 next = this.getPosition( percent + 0.001 ),\r
278                                 dir = vec3.normalize( vec3.direction( prev, next ) ),\r
279                                 cosValue = vec3.dot( dir, [1, 0, 0] );\r
280 \r
281                         return Math.acos( cosValue ) + Math.PI;\r
282                 }\r
283         } );\r
284 \r
285         $.motionpath = function ( type, data ) {\r
286                 var object = new MotionPath[type]();\r
287                 object.init( data );\r
288                 return object;\r
289         };\r
290 } ( jQuery, window ) );\r
291 \r
292 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);\r
293 } );\r
294 //>>excludeEnd("jqmBuildExclude");\r