dom.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. // Copyright 2005 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Predefined DHTML animations such as slide, resize and fade.
  16. *
  17. * @see ../demos/effects.html
  18. */
  19. goog.provide('goog.fx.dom');
  20. goog.provide('goog.fx.dom.BgColorTransform');
  21. goog.provide('goog.fx.dom.ColorTransform');
  22. goog.provide('goog.fx.dom.Fade');
  23. goog.provide('goog.fx.dom.FadeIn');
  24. goog.provide('goog.fx.dom.FadeInAndShow');
  25. goog.provide('goog.fx.dom.FadeOut');
  26. goog.provide('goog.fx.dom.FadeOutAndHide');
  27. goog.provide('goog.fx.dom.PredefinedEffect');
  28. goog.provide('goog.fx.dom.Resize');
  29. goog.provide('goog.fx.dom.ResizeHeight');
  30. goog.provide('goog.fx.dom.ResizeWidth');
  31. goog.provide('goog.fx.dom.Scroll');
  32. goog.provide('goog.fx.dom.Slide');
  33. goog.provide('goog.fx.dom.SlideFrom');
  34. goog.provide('goog.fx.dom.Swipe');
  35. goog.require('goog.color');
  36. goog.require('goog.events');
  37. goog.require('goog.fx.Animation');
  38. goog.require('goog.fx.Transition');
  39. goog.require('goog.style');
  40. goog.require('goog.style.bidi');
  41. goog.forwardDeclare('goog.events.EventHandler');
  42. /**
  43. * Abstract class that provides reusable functionality for predefined animations
  44. * that manipulate a single DOM element
  45. *
  46. * @param {Element} element Dom Node to be used in the animation.
  47. * @param {Array<number>} start Array for start coordinates.
  48. * @param {Array<number>} end Array for end coordinates.
  49. * @param {number} time Length of animation in milliseconds.
  50. * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
  51. * @extends {goog.fx.Animation}
  52. * @constructor
  53. * @struct
  54. */
  55. goog.fx.dom.PredefinedEffect = function(element, start, end, time, opt_acc) {
  56. goog.fx.Animation.call(this, start, end, time, opt_acc);
  57. /**
  58. * DOM Node that will be used in the animation
  59. * @type {Element}
  60. */
  61. this.element = element;
  62. /**
  63. * Whether the element is rendered right-to-left. We cache this here for
  64. * efficiency.
  65. * @private {boolean|undefined}
  66. */
  67. this.rightToLeft_;
  68. };
  69. goog.inherits(goog.fx.dom.PredefinedEffect, goog.fx.Animation);
  70. /**
  71. * Called to update the style of the element.
  72. * @protected
  73. */
  74. goog.fx.dom.PredefinedEffect.prototype.updateStyle = goog.nullFunction;
  75. /**
  76. * Whether the DOM element being manipulated is rendered right-to-left.
  77. * @return {boolean} True if the DOM element is rendered right-to-left, false
  78. * otherwise.
  79. */
  80. goog.fx.dom.PredefinedEffect.prototype.isRightToLeft = function() {
  81. if (!goog.isDef(this.rightToLeft_)) {
  82. this.rightToLeft_ = goog.style.isRightToLeft(this.element);
  83. }
  84. return this.rightToLeft_;
  85. };
  86. /** @override */
  87. goog.fx.dom.PredefinedEffect.prototype.onAnimate = function() {
  88. this.updateStyle();
  89. goog.fx.dom.PredefinedEffect.superClass_.onAnimate.call(this);
  90. };
  91. /** @override */
  92. goog.fx.dom.PredefinedEffect.prototype.onEnd = function() {
  93. this.updateStyle();
  94. goog.fx.dom.PredefinedEffect.superClass_.onEnd.call(this);
  95. };
  96. /** @override */
  97. goog.fx.dom.PredefinedEffect.prototype.onBegin = function() {
  98. this.updateStyle();
  99. goog.fx.dom.PredefinedEffect.superClass_.onBegin.call(this);
  100. };
  101. /**
  102. * Creates an animation object that will slide an element from A to B. (This
  103. * in effect automatically sets up the onanimate event for an Animation object)
  104. *
  105. * Start and End should be 2 dimensional arrays
  106. *
  107. * @param {Element} element Dom Node to be used in the animation.
  108. * @param {Array<number>} start 2D array for start coordinates (X, Y).
  109. * @param {Array<number>} end 2D array for end coordinates (X, Y).
  110. * @param {number} time Length of animation in milliseconds.
  111. * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
  112. * @extends {goog.fx.dom.PredefinedEffect}
  113. * @constructor
  114. * @struct
  115. */
  116. goog.fx.dom.Slide = function(element, start, end, time, opt_acc) {
  117. if (start.length != 2 || end.length != 2) {
  118. throw Error('Start and end points must be 2D');
  119. }
  120. goog.fx.dom.PredefinedEffect.apply(this, arguments);
  121. };
  122. goog.inherits(goog.fx.dom.Slide, goog.fx.dom.PredefinedEffect);
  123. /** @override */
  124. goog.fx.dom.Slide.prototype.updateStyle = function() {
  125. var pos = (this.isRightPositioningForRtlEnabled() && this.isRightToLeft()) ?
  126. 'right' :
  127. 'left';
  128. this.element.style[pos] = Math.round(this.coords[0]) + 'px';
  129. this.element.style.top = Math.round(this.coords[1]) + 'px';
  130. };
  131. /**
  132. * Slides an element from its current position.
  133. *
  134. * @param {Element} element DOM node to be used in the animation.
  135. * @param {Array<number>} end 2D array for end coordinates (X, Y).
  136. * @param {number} time Length of animation in milliseconds.
  137. * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
  138. * @extends {goog.fx.dom.Slide}
  139. * @constructor
  140. * @struct
  141. */
  142. goog.fx.dom.SlideFrom = function(element, end, time, opt_acc) {
  143. /** @type {?Array<number>} */
  144. this.startPoint;
  145. var offsetLeft = this.isRightPositioningForRtlEnabled() ?
  146. goog.style.bidi.getOffsetStart(element) :
  147. /** @type {!HTMLElement} */ (element).offsetLeft;
  148. var start = [offsetLeft, /** @type {!HTMLElement} */ (element).offsetTop];
  149. goog.fx.dom.Slide.call(this, element, start, end, time, opt_acc);
  150. };
  151. goog.inherits(goog.fx.dom.SlideFrom, goog.fx.dom.Slide);
  152. /** @override */
  153. goog.fx.dom.SlideFrom.prototype.onBegin = function() {
  154. var offsetLeft = this.isRightPositioningForRtlEnabled() ?
  155. goog.style.bidi.getOffsetStart(this.element) :
  156. this.element.offsetLeft;
  157. this.startPoint = [
  158. offsetLeft,
  159. /** @type {!HTMLElement} */ (this.element).offsetTop
  160. ];
  161. goog.fx.dom.SlideFrom.superClass_.onBegin.call(this);
  162. };
  163. /**
  164. * Creates an animation object that will slide an element into its final size.
  165. * Requires that the element is absolutely positioned.
  166. *
  167. * @param {Element} element Dom Node to be used in the animation.
  168. * @param {Array<number>} start 2D array for start size (W, H).
  169. * @param {Array<number>} end 2D array for end size (W, H).
  170. * @param {number} time Length of animation in milliseconds.
  171. * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
  172. * @extends {goog.fx.dom.PredefinedEffect}
  173. * @constructor
  174. * @struct
  175. */
  176. goog.fx.dom.Swipe = function(element, start, end, time, opt_acc) {
  177. if (start.length != 2 || end.length != 2) {
  178. throw Error('Start and end points must be 2D');
  179. }
  180. goog.fx.dom.PredefinedEffect.apply(this, arguments);
  181. /**
  182. * Maximum width for element.
  183. * @type {number}
  184. * @private
  185. */
  186. this.maxWidth_ = Math.max(this.endPoint[0], this.startPoint[0]);
  187. /**
  188. * Maximum height for element.
  189. * @type {number}
  190. * @private
  191. */
  192. this.maxHeight_ = Math.max(this.endPoint[1], this.startPoint[1]);
  193. };
  194. goog.inherits(goog.fx.dom.Swipe, goog.fx.dom.PredefinedEffect);
  195. /**
  196. * Animation event handler that will resize an element by setting its width,
  197. * height and clipping.
  198. * @protected
  199. * @override
  200. */
  201. goog.fx.dom.Swipe.prototype.updateStyle = function() {
  202. var x = this.coords[0];
  203. var y = this.coords[1];
  204. this.clip_(Math.round(x), Math.round(y), this.maxWidth_, this.maxHeight_);
  205. this.element.style.width = Math.round(x) + 'px';
  206. var marginX =
  207. (this.isRightPositioningForRtlEnabled() && this.isRightToLeft()) ?
  208. 'marginRight' :
  209. 'marginLeft';
  210. this.element.style[marginX] = Math.round(x) - this.maxWidth_ + 'px';
  211. this.element.style.marginTop = Math.round(y) - this.maxHeight_ + 'px';
  212. };
  213. /**
  214. * Helper function for setting element clipping.
  215. * @param {number} x Current element width.
  216. * @param {number} y Current element height.
  217. * @param {number} w Maximum element width.
  218. * @param {number} h Maximum element height.
  219. * @private
  220. */
  221. goog.fx.dom.Swipe.prototype.clip_ = function(x, y, w, h) {
  222. this.element.style.clip =
  223. 'rect(' + (h - y) + 'px ' + w + 'px ' + h + 'px ' + (w - x) + 'px)';
  224. };
  225. /**
  226. * Creates an animation object that will scroll an element from A to B.
  227. *
  228. * Start and End should be 2 dimensional arrays
  229. *
  230. * @param {Element} element Dom Node to be used in the animation.
  231. * @param {Array<number>} start 2D array for start scroll left and top.
  232. * @param {Array<number>} end 2D array for end scroll left and top.
  233. * @param {number} time Length of animation in milliseconds.
  234. * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
  235. * @extends {goog.fx.dom.PredefinedEffect}
  236. * @constructor
  237. * @struct
  238. */
  239. goog.fx.dom.Scroll = function(element, start, end, time, opt_acc) {
  240. if (start.length != 2 || end.length != 2) {
  241. throw Error('Start and end points must be 2D');
  242. }
  243. goog.fx.dom.PredefinedEffect.apply(this, arguments);
  244. };
  245. goog.inherits(goog.fx.dom.Scroll, goog.fx.dom.PredefinedEffect);
  246. /**
  247. * Animation event handler that will set the scroll position of an element.
  248. * @protected
  249. * @override
  250. */
  251. goog.fx.dom.Scroll.prototype.updateStyle = function() {
  252. if (this.isRightPositioningForRtlEnabled()) {
  253. goog.style.bidi.setScrollOffset(this.element, Math.round(this.coords[0]));
  254. } else {
  255. this.element.scrollLeft = Math.round(this.coords[0]);
  256. }
  257. this.element.scrollTop = Math.round(this.coords[1]);
  258. };
  259. /**
  260. * Creates an animation object that will resize an element between two widths
  261. * and heights.
  262. *
  263. * Start and End should be 2 dimensional arrays
  264. *
  265. * @param {Element} element Dom Node to be used in the animation.
  266. * @param {Array<number>} start 2D array for start width and height.
  267. * @param {Array<number>} end 2D array for end width and height.
  268. * @param {number} time Length of animation in milliseconds.
  269. * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
  270. * @extends {goog.fx.dom.PredefinedEffect}
  271. * @constructor
  272. * @struct
  273. */
  274. goog.fx.dom.Resize = function(element, start, end, time, opt_acc) {
  275. if (start.length != 2 || end.length != 2) {
  276. throw Error('Start and end points must be 2D');
  277. }
  278. goog.fx.dom.PredefinedEffect.apply(this, arguments);
  279. };
  280. goog.inherits(goog.fx.dom.Resize, goog.fx.dom.PredefinedEffect);
  281. /**
  282. * Animation event handler that will resize an element by setting its width and
  283. * height.
  284. * @protected
  285. * @override
  286. */
  287. goog.fx.dom.Resize.prototype.updateStyle = function() {
  288. this.element.style.width = Math.round(this.coords[0]) + 'px';
  289. this.element.style.height = Math.round(this.coords[1]) + 'px';
  290. };
  291. /**
  292. * Creates an animation object that will resize an element between two widths
  293. *
  294. * Start and End should be numbers
  295. *
  296. * @param {Element} element Dom Node to be used in the animation.
  297. * @param {number} start Start width.
  298. * @param {number} end End width.
  299. * @param {number} time Length of animation in milliseconds.
  300. * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
  301. * @extends {goog.fx.dom.PredefinedEffect}
  302. * @constructor
  303. * @struct
  304. */
  305. goog.fx.dom.ResizeWidth = function(element, start, end, time, opt_acc) {
  306. goog.fx.dom.PredefinedEffect.call(
  307. this, element, [start], [end], time, opt_acc);
  308. };
  309. goog.inherits(goog.fx.dom.ResizeWidth, goog.fx.dom.PredefinedEffect);
  310. /**
  311. * Animation event handler that will resize an element by setting its width.
  312. * @protected
  313. * @override
  314. */
  315. goog.fx.dom.ResizeWidth.prototype.updateStyle = function() {
  316. this.element.style.width = Math.round(this.coords[0]) + 'px';
  317. };
  318. /**
  319. * Creates an animation object that will resize an element between two heights
  320. *
  321. * Start and End should be numbers
  322. *
  323. * @param {Element} element Dom Node to be used in the animation.
  324. * @param {number} start Start height.
  325. * @param {number} end End height.
  326. * @param {number} time Length of animation in milliseconds.
  327. * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
  328. * @extends {goog.fx.dom.PredefinedEffect}
  329. * @constructor
  330. * @struct
  331. */
  332. goog.fx.dom.ResizeHeight = function(element, start, end, time, opt_acc) {
  333. goog.fx.dom.PredefinedEffect.call(
  334. this, element, [start], [end], time, opt_acc);
  335. };
  336. goog.inherits(goog.fx.dom.ResizeHeight, goog.fx.dom.PredefinedEffect);
  337. /**
  338. * Animation event handler that will resize an element by setting its height.
  339. * @protected
  340. * @override
  341. */
  342. goog.fx.dom.ResizeHeight.prototype.updateStyle = function() {
  343. this.element.style.height = Math.round(this.coords[0]) + 'px';
  344. };
  345. /**
  346. * Creates an animation object that fades the opacity of an element between two
  347. * limits.
  348. *
  349. * Start and End should be floats between 0 and 1
  350. *
  351. * @param {Element} element Dom Node to be used in the animation.
  352. * @param {Array<number>|number} start 1D Array or Number with start opacity.
  353. * @param {Array<number>|number} end 1D Array or Number for end opacity.
  354. * @param {number} time Length of animation in milliseconds.
  355. * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
  356. * @extends {goog.fx.dom.PredefinedEffect}
  357. * @constructor
  358. * @struct
  359. */
  360. goog.fx.dom.Fade = function(element, start, end, time, opt_acc) {
  361. if (goog.isNumber(start)) start = [start];
  362. if (goog.isNumber(end)) end = [end];
  363. goog.fx.dom.Fade.base(
  364. this, 'constructor', element, start, end, time, opt_acc);
  365. if (start.length != 1 || end.length != 1) {
  366. throw Error('Start and end points must be 1D');
  367. }
  368. /**
  369. * The last opacity we set, or -1 for not set.
  370. * @private {number}
  371. */
  372. this.lastOpacityUpdate_ = goog.fx.dom.Fade.OPACITY_UNSET_;
  373. };
  374. goog.inherits(goog.fx.dom.Fade, goog.fx.dom.PredefinedEffect);
  375. /**
  376. * The quantization of opacity values to use.
  377. * @private {number}
  378. */
  379. goog.fx.dom.Fade.TOLERANCE_ = 1.0 / 0x400; // 10-bit color
  380. /**
  381. * Value indicating that the opacity must be set on next update.
  382. * @private {number}
  383. */
  384. goog.fx.dom.Fade.OPACITY_UNSET_ = -1;
  385. /**
  386. * Animation event handler that will set the opacity of an element.
  387. * @protected
  388. * @override
  389. */
  390. goog.fx.dom.Fade.prototype.updateStyle = function() {
  391. var opacity = this.coords[0];
  392. var delta = Math.abs(opacity - this.lastOpacityUpdate_);
  393. // In order to keep eager browsers from over-rendering, only update
  394. // on a potentially visible change in opacity.
  395. if (delta >= goog.fx.dom.Fade.TOLERANCE_) {
  396. goog.style.setOpacity(this.element, opacity);
  397. this.lastOpacityUpdate_ = opacity;
  398. }
  399. };
  400. /** @override */
  401. goog.fx.dom.Fade.prototype.onBegin = function() {
  402. this.lastOpacityUpdate_ = goog.fx.dom.Fade.OPACITY_UNSET_;
  403. goog.fx.dom.Fade.base(this, 'onBegin');
  404. };
  405. /** @override */
  406. goog.fx.dom.Fade.prototype.onEnd = function() {
  407. this.lastOpacityUpdate_ = goog.fx.dom.Fade.OPACITY_UNSET_;
  408. goog.fx.dom.Fade.base(this, 'onEnd');
  409. };
  410. /**
  411. * Animation event handler that will show the element.
  412. */
  413. goog.fx.dom.Fade.prototype.show = function() {
  414. this.element.style.display = '';
  415. };
  416. /**
  417. * Animation event handler that will hide the element
  418. */
  419. goog.fx.dom.Fade.prototype.hide = function() {
  420. this.element.style.display = 'none';
  421. };
  422. /**
  423. * Fades an element out from full opacity to completely transparent.
  424. *
  425. * @param {Element} element Dom Node to be used in the animation.
  426. * @param {number} time Length of animation in milliseconds.
  427. * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
  428. * @extends {goog.fx.dom.Fade}
  429. * @constructor
  430. * @struct
  431. */
  432. goog.fx.dom.FadeOut = function(element, time, opt_acc) {
  433. goog.fx.dom.Fade.call(this, element, 1, 0, time, opt_acc);
  434. };
  435. goog.inherits(goog.fx.dom.FadeOut, goog.fx.dom.Fade);
  436. /**
  437. * Fades an element in from completely transparent to fully opacity.
  438. *
  439. * @param {Element} element Dom Node to be used in the animation.
  440. * @param {number} time Length of animation in milliseconds.
  441. * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
  442. * @extends {goog.fx.dom.Fade}
  443. * @constructor
  444. * @struct
  445. */
  446. goog.fx.dom.FadeIn = function(element, time, opt_acc) {
  447. goog.fx.dom.Fade.call(this, element, 0, 1, time, opt_acc);
  448. };
  449. goog.inherits(goog.fx.dom.FadeIn, goog.fx.dom.Fade);
  450. /**
  451. * Fades an element out from full opacity to completely transparent and then
  452. * sets the display to 'none'
  453. *
  454. * @param {Element} element Dom Node to be used in the animation.
  455. * @param {number} time Length of animation in milliseconds.
  456. * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
  457. * @extends {goog.fx.dom.Fade}
  458. * @constructor
  459. * @struct
  460. */
  461. goog.fx.dom.FadeOutAndHide = function(element, time, opt_acc) {
  462. goog.fx.dom.Fade.call(this, element, 1, 0, time, opt_acc);
  463. };
  464. goog.inherits(goog.fx.dom.FadeOutAndHide, goog.fx.dom.Fade);
  465. /** @override */
  466. goog.fx.dom.FadeOutAndHide.prototype.onBegin = function() {
  467. this.show();
  468. goog.fx.dom.FadeOutAndHide.superClass_.onBegin.call(this);
  469. };
  470. /** @override */
  471. goog.fx.dom.FadeOutAndHide.prototype.onEnd = function() {
  472. this.hide();
  473. goog.fx.dom.FadeOutAndHide.superClass_.onEnd.call(this);
  474. };
  475. /**
  476. * Sets an element's display to be visible and then fades an element in from
  477. * completely transparent to fully opaque.
  478. *
  479. * @param {Element} element Dom Node to be used in the animation.
  480. * @param {number} time Length of animation in milliseconds.
  481. * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
  482. * @extends {goog.fx.dom.Fade}
  483. * @constructor
  484. * @struct
  485. */
  486. goog.fx.dom.FadeInAndShow = function(element, time, opt_acc) {
  487. goog.fx.dom.Fade.call(this, element, 0, 1, time, opt_acc);
  488. };
  489. goog.inherits(goog.fx.dom.FadeInAndShow, goog.fx.dom.Fade);
  490. /** @override */
  491. goog.fx.dom.FadeInAndShow.prototype.onBegin = function() {
  492. this.show();
  493. goog.fx.dom.FadeInAndShow.superClass_.onBegin.call(this);
  494. };
  495. /**
  496. * Provides a transformation of an elements background-color.
  497. *
  498. * Start and End should be 3D arrays representing R,G,B
  499. *
  500. * @param {Element} element Dom Node to be used in the animation.
  501. * @param {Array<number>} start 3D Array for RGB of start color.
  502. * @param {Array<number>} end 3D Array for RGB of end color.
  503. * @param {number} time Length of animation in milliseconds.
  504. * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
  505. * @extends {goog.fx.dom.PredefinedEffect}
  506. * @constructor
  507. * @struct
  508. */
  509. goog.fx.dom.BgColorTransform = function(element, start, end, time, opt_acc) {
  510. if (start.length != 3 || end.length != 3) {
  511. throw Error('Start and end points must be 3D');
  512. }
  513. goog.fx.dom.PredefinedEffect.apply(this, arguments);
  514. };
  515. goog.inherits(goog.fx.dom.BgColorTransform, goog.fx.dom.PredefinedEffect);
  516. /**
  517. * Animation event handler that will set the background-color of an element
  518. */
  519. goog.fx.dom.BgColorTransform.prototype.setColor = function() {
  520. var coordsAsInts = [];
  521. for (var i = 0; i < this.coords.length; i++) {
  522. coordsAsInts[i] = Math.round(this.coords[i]);
  523. }
  524. var color = 'rgb(' + coordsAsInts.join(',') + ')';
  525. this.element.style.backgroundColor = color;
  526. };
  527. /** @override */
  528. goog.fx.dom.BgColorTransform.prototype.updateStyle = function() {
  529. this.setColor();
  530. };
  531. /**
  532. * Fade elements background color from start color to the element's current
  533. * background color.
  534. *
  535. * Start should be a 3D array representing R,G,B
  536. *
  537. * @param {Element} element Dom Node to be used in the animation.
  538. * @param {Array<number>} start 3D Array for RGB of start color.
  539. * @param {number} time Length of animation in milliseconds.
  540. * @param {goog.events.EventHandler=} opt_eventHandler Optional event handler
  541. * to use when listening for events.
  542. */
  543. goog.fx.dom.bgColorFadeIn = function(element, start, time, opt_eventHandler) {
  544. var initialBgColor = element.style.backgroundColor || '';
  545. var computedBgColor = goog.style.getBackgroundColor(element);
  546. var end;
  547. if (computedBgColor && computedBgColor != 'transparent' &&
  548. computedBgColor != 'rgba(0, 0, 0, 0)') {
  549. end = goog.color.hexToRgb(goog.color.parse(computedBgColor).hex);
  550. } else {
  551. end = [255, 255, 255];
  552. }
  553. var anim = new goog.fx.dom.BgColorTransform(element, start, end, time);
  554. function setBgColor() { element.style.backgroundColor = initialBgColor; }
  555. if (opt_eventHandler) {
  556. opt_eventHandler.listen(anim, goog.fx.Transition.EventType.END, setBgColor);
  557. } else {
  558. goog.events.listen(anim, goog.fx.Transition.EventType.END, setBgColor);
  559. }
  560. anim.play();
  561. };
  562. /**
  563. * Provides a transformation of an elements color.
  564. *
  565. * @param {Element} element Dom Node to be used in the animation.
  566. * @param {Array<number>} start 3D Array representing R,G,B.
  567. * @param {Array<number>} end 3D Array representing R,G,B.
  568. * @param {number} time Length of animation in milliseconds.
  569. * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
  570. * @constructor
  571. * @struct
  572. * @extends {goog.fx.dom.PredefinedEffect}
  573. */
  574. goog.fx.dom.ColorTransform = function(element, start, end, time, opt_acc) {
  575. if (start.length != 3 || end.length != 3) {
  576. throw Error('Start and end points must be 3D');
  577. }
  578. goog.fx.dom.PredefinedEffect.apply(this, arguments);
  579. };
  580. goog.inherits(goog.fx.dom.ColorTransform, goog.fx.dom.PredefinedEffect);
  581. /**
  582. * Animation event handler that will set the color of an element.
  583. * @protected
  584. * @override
  585. */
  586. goog.fx.dom.ColorTransform.prototype.updateStyle = function() {
  587. var coordsAsInts = [];
  588. for (var i = 0; i < this.coords.length; i++) {
  589. coordsAsInts[i] = Math.round(this.coords[i]);
  590. }
  591. var color = 'rgb(' + coordsAsInts.join(',') + ')';
  592. this.element.style.color = color;
  593. };