Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / polymer / components-chromium / paper-ripple / raw-extracted.js
1
2
3 //
4 // INK EQUATIONS
5 //
6
7 // Animation constants.
8 var globalSpeed = 1;
9 var waveOpacityDecayVelocity = 0.8 / globalSpeed;  // opacity per second.
10 var waveInitialOpacity = 0.25;
11 var waveLingerOnTouchUp = 0.2;
12 var waveMaxRadius = 150; 
13
14 // TODOs:
15 // - rather than max distance to corner, use hypotenuos(sp) (diag)
16 // - use quadratic for the fall off, move fast at the beginning, 
17 // - on cancel, immediately fade out, reverse the direction
18
19 function waveRadiusFn(touchDownMs, touchUpMs, ww, hh) {
20   // Convert from ms to s.
21   var touchDown = touchDownMs / 1000;
22   var touchUp = touchUpMs / 1000;
23   var totalElapsed = touchDown + touchUp;
24   var waveRadius = Math.min(Math.max(ww, hh), waveMaxRadius) * 1.1 + 5;
25   var dduration = 1.1 - .2 * (waveRadius / waveMaxRadius);
26   var tt = (totalElapsed / dduration);
27   
28   var ssize = waveRadius * (1 - Math.pow(80, -tt));
29   return Math.abs(ssize);
30 }
31
32 function waveOpacityFn(td, tu) {
33   // Convert from ms to s.
34   var touchDown = td / 1000;
35   var touchUp = tu / 1000;
36   var totalElapsed = touchDown + touchUp;
37
38   if (tu <= 0) {  // before touch up
39     return waveInitialOpacity;
40   }
41   return Math.max(0, waveInitialOpacity - touchUp * waveOpacityDecayVelocity);
42 }
43
44 function waveOuterOpacityFn(td, tu) {
45   // Convert from ms to s.
46   var touchDown = td / 1000;
47   var touchUp = tu / 1000;
48
49   // Linear increase in background opacity, capped at the opacity
50   // of the wavefront (waveOpacity).
51   var outerOpacity = touchDown * 0.3;
52   var waveOpacity = waveOpacityFn(td, tu);
53   return Math.max(0, Math.min(outerOpacity, waveOpacity));
54   
55 }
56
57 function waveGravityToCenterPercentageFn(td, tu, r) {
58   // Convert from ms to s.
59   var touchDown = td / 1000;
60   var touchUp = tu / 1000;
61   var totalElapsed = touchDown + touchUp;
62
63   return Math.min(1.0, touchUp * 6);
64 }
65
66
67 // Determines whether the wave should be completely removed.
68 function waveDidFinish(wave, radius) {
69   var waveOpacity = waveOpacityFn(wave.tDown, wave.tUp);
70   // Does not linger any more.
71   // var lingerTimeMs = waveLingerOnTouchUp * 1000;
72
73   // If the wave opacity is 0 and the radius exceeds the bounds
74   // of the element, then this is finished.
75   if (waveOpacity < 0.01 && radius >= wave.maxRadius) {
76     return true;
77   }
78   return false;
79 };
80
81 //
82 // DRAWING
83 //
84
85 function animateIcon() {
86   var el = document.getElementById('button_toolbar0');
87   el.classList.add('animate');
88   setTimeout(function(){
89     el.classList.remove('animate');
90     el.classList.toggle('selected');
91   }, 500);
92 }
93
94
95 function drawRipple(canvas, x, y, radius, innerColor, outerColor, innerColorAlpha, outerColorAlpha) {
96   var ctx = canvas.getContext('2d');
97   if (outerColor) {
98     ctx.fillStyle = outerColor;
99     ctx.fillRect(0,0,canvas.width, canvas.height);
100   }
101
102   ctx.beginPath();
103   ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
104   ctx.fillStyle = innerColor;
105   ctx.fill();
106 }
107
108 function drawLabel(canvas, label, fontSize, color, alignment) {
109   var ctx = canvas.getContext('2d');
110   ctx.font= fontSize + 'px Helvetica';
111
112   var metrics = ctx.measureText(label);
113   var width = metrics.width;
114   var height = metrics.height;
115   ctx.fillStyle = color;
116
117   var xPos = (canvas.width/2 - width)/2;
118
119   if (alignment === 'left') { xPos = 16; }
120
121   ctx.fillText(label, xPos, canvas.height/2 - (canvas.height/2 - fontSize +2) / 2);
122 }
123
124 //
125 // BUTTON SETUP
126 //
127
128 function createWave(elem) {
129   var elementStyle = window.getComputedStyle(elem);
130   var fgColor = elementStyle.color;
131
132   var wave = {
133     waveColor: fgColor,
134     maxRadius: 0,
135     isMouseDown: false,
136     mouseDownStart: 0.0,
137     mouseUpStart: 0.0,
138     tDown: 0,
139     tUp: 0
140   };
141   return wave;
142 }
143
144 function removeWaveFromScope(scope, wave) {
145   if (scope.waves) {
146     var pos = scope.waves.indexOf(wave);
147     scope.waves.splice(pos, 1);
148   }
149 };
150
151
152 function setUpPaperByClass( classname ) {
153   var elems = document.querySelectorAll( classname );
154   [].forEach.call( elems, function( el ) {
155       setUpPaper(el);
156   });
157 }
158
159 function setUpPaper(elem) {
160   var pixelDensity = 2;
161
162   var elementStyle = window.getComputedStyle(elem);
163   var fgColor = elementStyle.color;
164   var bgColor = elementStyle.backgroundColor;
165   elem.width = elem.clientWidth;
166   elem.setAttribute('width', elem.clientWidth * pixelDensity + "px");
167   elem.setAttribute('height', elem.clientHeight * pixelDensity + "px");
168
169   var isButton = elem.classList.contains( 'button' ) || elem.classList.contains( 'button_floating' ) | elem.classList.contains( 'button_menu' );
170   var isToolbarButton =  elem.classList.contains( 'button_toolbar' );
171
172   elem.getContext('2d').scale(pixelDensity, pixelDensity)
173
174   var scope = {
175     backgroundFill: true,
176     element: elem,
177     label: 'Button',
178     waves: [],
179   };
180
181
182   scope.label = elem.getAttribute('value') || elementStyle.content;
183   scope.labelFontSize = elementStyle.fontSize.split("px")[0];
184
185   drawLabel(elem, scope.label, scope.labelFontSize, fgColor, elem.style.textAlign);
186
187
188   //
189   // RENDER FOR EACH FRAME
190   //
191   var onFrame = function() {
192     var shouldRenderNextFrame = false;
193
194     // Clear the canvas
195     var ctx = elem.getContext('2d');
196     ctx.clearRect(0, 0, elem.width, elem.height);
197
198     var deleteTheseWaves = [];
199     // The oldest wave's touch down duration
200     var longestTouchDownDuration = 0;
201     var longestTouchUpDuration = 0;
202     // Save the last known wave color
203     var lastWaveColor = null;
204
205     for (var i = 0; i < scope.waves.length; i++) {
206       var wave = scope.waves[i];
207
208       if (wave.mouseDownStart > 0) {
209         wave.tDown = now() - wave.mouseDownStart;
210       }
211       if (wave.mouseUpStart > 0) {
212         wave.tUp = now() - wave.mouseUpStart;
213       }
214
215       // Determine how long the touch has been up or down.
216       var tUp = wave.tUp;
217       var tDown = wave.tDown;
218       longestTouchDownDuration = Math.max(longestTouchDownDuration, tDown);
219       longestTouchUpDuration = Math.max(longestTouchUpDuration, tUp);
220
221       // Obtain the instantenous size and alpha of the ripple.
222       var radius = waveRadiusFn(tDown, tUp, elem.width, elem.height);
223       var waveAlpha =  waveOpacityFn(tDown, tUp);
224       var waveColor = cssColorWithAlpha(wave.waveColor, waveAlpha);
225       lastWaveColor = wave.waveColor;
226
227       // Position of the ripple.
228       var x = wave.startPosition.x;
229       var y = wave.startPosition.y;
230
231       // Ripple gravitational pull to the center of the canvas.
232       if (wave.endPosition) {
233  
234         var translateFraction = waveGravityToCenterPercentageFn(tDown, tUp, wave.maxRadius);
235
236         // This translates from the origin to the center of the view  based on the max dimension of  
237         var translateFraction = Math.min(1, radius / wave.containerSize * 2 / Math.sqrt(2) );
238
239         x += translateFraction * (wave.endPosition.x - wave.startPosition.x);
240         y += translateFraction * (wave.endPosition.y - wave.startPosition.y);
241       }
242
243       // If we do a background fill fade too, work out the correct color.
244       var bgFillColor = null;
245       if (scope.backgroundFill) {
246         var bgFillAlpha = waveOuterOpacityFn(tDown, tUp);
247         bgFillColor = cssColorWithAlpha(wave.waveColor, bgFillAlpha);
248       }
249
250       // Draw the ripple.
251       drawRipple(elem, x, y, radius, waveColor, bgFillColor);
252
253       // Determine whether there is any more rendering to be done.
254       var shouldRenderWaveAgain = !waveDidFinish(wave, radius);
255       shouldRenderNextFrame = shouldRenderNextFrame || shouldRenderWaveAgain;
256       if (!shouldRenderWaveAgain) {
257         deleteTheseWaves.push(wave);
258       }
259    }
260
261     if (shouldRenderNextFrame) {
262       window.requestAnimationFrame(onFrame);
263     }  else {
264       // If there is nothing to draw, clear any drawn waves now because
265       // we're not going to get another requestAnimationFrame any more.
266       var ctx = elem.getContext('2d');
267       ctx.clearRect(0, 0, elem.width, elem.height);
268     }
269
270     // Draw the label at the very last point so it is on top of everything.
271     drawLabel(elem, scope.label, scope.labelFontSize, fgColor, elem.style.textAlign);
272
273     for (var i = 0; i < deleteTheseWaves.length; ++i) {
274       var wave = deleteTheseWaves[i];
275       removeWaveFromScope(scope, wave);
276     }
277   };
278
279   //
280   // MOUSE DOWN HANDLER
281   //
282
283   elem.addEventListener('mousedown', function(e) {
284     var wave = createWave(e.target);
285     var elem = scope.element;
286
287     wave.isMouseDown = true;
288     wave.tDown = 0.0;
289     wave.tUp = 0.0;
290     wave.mouseUpStart = 0.0;
291     wave.mouseDownStart = now();
292
293     var width = e.target.width / 2; // Retina canvas
294     var height = e.target.height / 2;
295     var touchX = e.clientX - e.target.offsetLeft - e.target.offsetParent.offsetLeft;
296     var touchY = e.clientY - e.target.offsetTop - e.target.offsetParent.offsetTop;
297     wave.startPosition = {x:touchX, y:touchY};
298
299     if (elem.classList.contains("recenteringTouch")) {
300       wave.endPosition = {x: width / 2,  y: height / 2};
301       wave.slideDistance = dist(wave.startPosition, wave.endPosition);
302     }
303     wave.containerSize = Math.max(width, height);
304     wave.maxRadius = distanceFromPointToFurthestCorner(wave.startPosition, {w: width, h: height});
305     elem.classList.add("activated");
306     scope.waves.push(wave);
307     window.requestAnimationFrame(onFrame);
308     return false;
309   });
310
311   //
312   // MOUSE UP HANDLER
313   //
314
315   elem.addEventListener('mouseup', function(e) {
316     elem.classList.remove("activated");
317
318     for (var i = 0; i < scope.waves.length; i++) {
319       // Declare the next wave that has mouse down to be mouse'ed up.
320       var wave = scope.waves[i];
321       if (wave.isMouseDown) {
322         wave.isMouseDown = false
323         wave.mouseUpStart = now();
324         wave.mouseDownStart = 0;
325         wave.tUp = 0.0;
326         break;
327       }
328     }
329     return false;
330   });
331
332   elem.addEventListener('mouseout', function(e) {
333   elem.classList.remove("activated");
334
335   for (var i = 0; i < scope.waves.length; i++) {
336     // Declare the next wave that has mouse down to be mouse'ed up.
337     var wave = scope.waves[i];
338     if (wave.isMouseDown) {
339       wave.isMouseDown = false
340       wave.mouseUpStart = now();
341       wave.mouseDownStart = 0;
342       wave.tUp = 0.0;
343       wave.cancelled = true;
344       break;
345     }
346   }
347   return false;
348   });
349
350   return scope;
351 };
352
353 // Shortcuts.
354 var pow = Math.pow;
355 var now = function() { return new Date().getTime(); };
356
357 // Quad beizer where t is between 0 and 1.
358 function quadBezier(t, p0, p1, p2, p3) {
359   return pow(1 - t, 3) * p0 +
360          3 * pow(1 - t, 2) * t * p1 +
361          (1 - t) * pow(t, 2) * p2 +
362          pow(t, 3) * p3;
363 }
364
365 function easeIn(t) {
366   return quadBezier(t, 0.4, 0.0, 1, 1);
367 }
368
369 function cssColorWithAlpha(cssColor, alpha) {
370     var parts = cssColor.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
371     if (typeof alpha == 'undefined') {
372         alpha = 1;
373     }
374     if (!parts) {
375       return 'rgba(255, 255, 255, ' + alpha + ')';
376     }
377     return 'rgba(' + parts[1] + ', ' + parts[2] + ', ' + parts[3] + ', ' + alpha + ')';
378 }
379
380 function dist(p1, p2) {
381   return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
382 }
383
384 function distanceFromPointToFurthestCorner(point, size) {
385   var tl_d = dist(point, {x: 0, y: 0});
386   var tr_d = dist(point, {x: size.w, y: 0});
387   var bl_d = dist(point, {x: 0, y: size.h});
388   var br_d = dist(point, {x: size.w, y: size.h});
389   return Math.max(Math.max(tl_d, tr_d), Math.max(bl_d, br_d));
390 }
391
392
393 function toggleDialog() {
394   var el = document.getElementById('dialog');
395   el.classList.toggle("visible");
396 }
397
398 function toggleMenu() {
399   var el = document.getElementById('menu');
400   el.classList.toggle("visible");
401 }
402
403
404 // Initialize
405
406 function init() {
407     setUpPaperByClass( '.paper' );
408 }
409
410 window.addEventListener('DOMContentLoaded', init, false);