flip.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.fx.flip"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.fx.flip"] = true;
  8. dojo.provide("dojox.fx.flip");
  9. dojo.require("dojo.fx");
  10. dojo.experimental("dojox.fx.flip");
  11. // because ShrinkSafe will eat this up:
  12. var borderConst = "border",
  13. widthConst = "Width",
  14. heightConst = "Height",
  15. topConst = "Top",
  16. rightConst = "Right",
  17. leftConst = "Left",
  18. bottomConst = "Bottom"
  19. ;
  20. dojox.fx.flip = function(/*Object*/ args){
  21. // summary: Animate a node flipping following a specific direction
  22. //
  23. // description:
  24. // Returns an animation that will flip the
  25. // node around a central axis:
  26. // if args.dir is "left" or "right" --> y axis
  27. // if args.dir is "top" or "bottom" --> x axis
  28. //
  29. // This effect is obtained using a border distorsion applied to a helper node.
  30. //
  31. // The user can specify three background colors for the helper node:
  32. // darkColor: the darkest color reached during the animation
  33. // lightColor: the brightest color
  34. // endColor: the final backgroundColor for the node
  35. //
  36. // depth: Float
  37. // 0 <= depth <= 1 overrides the computed "depth"
  38. // (0: min distorsion, 1: max distorsion)
  39. //
  40. // whichAnim: String
  41. // "first" : the first half animation
  42. // "last" : the second one
  43. // "both" (default) : both
  44. //
  45. // axis: String
  46. // "center" (default) : the node is flipped around his center
  47. // "shortside" : the node is flipped around his "short" (in perspective) side
  48. // "longside" : the node is flipped around his "long" (in perspective) side
  49. // "cube" : the node flips around the central axis of the cube
  50. //
  51. // shift: Integer
  52. // node translation, perpendicular to the rotation axis
  53. //
  54. // example:
  55. // | var anim = dojox.fx.flip({
  56. // | node: dojo.byId("nodeId"),
  57. // | dir: "top",
  58. // | darkColor: "#555555",
  59. // | lightColor: "#dddddd",
  60. // | endColor: "#666666",
  61. // | depth: .5,
  62. // | shift: 50,
  63. // | duration:300
  64. // | });
  65. var helperNode = dojo.create("div"),
  66. node = args.node = dojo.byId(args.node),
  67. s = node.style,
  68. dims = null,
  69. hs = null,
  70. pn = null,
  71. lightColor = args.lightColor || "#dddddd",
  72. darkColor = args.darkColor || "#555555",
  73. bgColor = dojo.style(node, "backgroundColor"),
  74. endColor = args.endColor || bgColor,
  75. staticProps = {},
  76. anims = [],
  77. duration = args.duration ? args.duration / 2 : 250,
  78. dir = args.dir || "left",
  79. pConst = .9,
  80. transparentColor = "transparent",
  81. whichAnim = args.whichAnim,
  82. axis = args.axis || "center",
  83. depth = args.depth
  84. ;
  85. // IE6 workaround: IE6 doesn't support transparent borders
  86. var convertColor = function(color){
  87. return ((new dojo.Color(color)).toHex() === "#000000") ? "#000001" : color;
  88. };
  89. if(dojo.isIE < 7){
  90. endColor = convertColor(endColor);
  91. lightColor = convertColor(lightColor);
  92. darkColor = convertColor(darkColor);
  93. bgColor = convertColor(bgColor);
  94. transparentColor = "black";
  95. helperNode.style.filter = "chroma(color='#000000')";
  96. }
  97. var init = (function(n){
  98. return function(){
  99. var ret = dojo.coords(n, true);
  100. dims = {
  101. top: ret.y,
  102. left: ret.x,
  103. width: ret.w,
  104. height: ret.h
  105. };
  106. }
  107. })(node);
  108. init();
  109. // helperNode initialization
  110. hs = {
  111. position: "absolute",
  112. top: dims["top"] + "px",
  113. left: dims["left"] + "px",
  114. height: "0",
  115. width: "0",
  116. zIndex: args.zIndex || (s.zIndex || 0),
  117. border: "0 solid " + transparentColor,
  118. fontSize: "0",
  119. visibility: "hidden"
  120. };
  121. var props = [ {},
  122. {
  123. top: dims["top"],
  124. left: dims["left"]
  125. }
  126. ];
  127. var dynProperties = {
  128. left: [leftConst, rightConst, topConst, bottomConst, widthConst, heightConst, "end" + heightConst + "Min", leftConst, "end" + heightConst + "Max"],
  129. right: [rightConst, leftConst, topConst, bottomConst, widthConst, heightConst, "end" + heightConst + "Min", leftConst, "end" + heightConst + "Max"],
  130. top: [topConst, bottomConst, leftConst, rightConst, heightConst, widthConst, "end" + widthConst + "Min", topConst, "end" + widthConst + "Max"],
  131. bottom: [bottomConst, topConst, leftConst, rightConst, heightConst, widthConst, "end" + widthConst + "Min", topConst, "end" + widthConst + "Max"]
  132. };
  133. // property names
  134. pn = dynProperties[dir];
  135. // .4 <= pConst <= .9
  136. if(typeof depth != "undefined"){
  137. depth = Math.max(0, Math.min(1, depth)) / 2;
  138. pConst = .4 + (.5 - depth);
  139. }else{
  140. pConst = Math.min(.9, Math.max(.4, dims[pn[5].toLowerCase()] / dims[pn[4].toLowerCase()]));
  141. }
  142. var p0 = props[0];
  143. for(var i = 4; i < 6; i++){
  144. if(axis == "center" || axis == "cube"){ // find a better name for "cube"
  145. dims["end" + pn[i] + "Min"] = dims[pn[i].toLowerCase()] * pConst;
  146. dims["end" + pn[i] + "Max"] = dims[pn[i].toLowerCase()] / pConst;
  147. }else if(axis == "shortside"){
  148. dims["end" + pn[i] + "Min"] = dims[pn[i].toLowerCase()];
  149. dims["end" + pn[i] + "Max"] = dims[pn[i].toLowerCase()] / pConst;
  150. }else if(axis == "longside"){
  151. dims["end" + pn[i] + "Min"] = dims[pn[i].toLowerCase()] * pConst;
  152. dims["end" + pn[i] + "Max"] = dims[pn[i].toLowerCase()];
  153. }
  154. }
  155. if(axis == "center"){
  156. p0[pn[2].toLowerCase()] = dims[pn[2].toLowerCase()] - (dims[pn[8]] - dims[pn[6]]) / 4;
  157. }else if(axis == "shortside"){
  158. p0[pn[2].toLowerCase()] = dims[pn[2].toLowerCase()] - (dims[pn[8]] - dims[pn[6]]) / 2;
  159. }
  160. staticProps[pn[5].toLowerCase()] = dims[pn[5].toLowerCase()] + "px";
  161. staticProps[pn[4].toLowerCase()] = "0";
  162. staticProps[borderConst + pn[1] + widthConst] = dims[pn[4].toLowerCase()] + "px";
  163. staticProps[borderConst + pn[1] + "Color"] = bgColor;
  164. p0[borderConst + pn[1] + widthConst] = 0;
  165. p0[borderConst + pn[1] + "Color"] = darkColor;
  166. p0[borderConst + pn[2] + widthConst] = p0[borderConst + pn[3] + widthConst] = axis != "cube"
  167. ? (dims["end" + pn[5] + "Max"] - dims["end" + pn[5] + "Min"]) / 2
  168. : dims[pn[6]] / 2
  169. ;
  170. p0[pn[7].toLowerCase()] = dims[pn[7].toLowerCase()] + dims[pn[4].toLowerCase()] / 2 + (args.shift || 0);
  171. p0[pn[5].toLowerCase()] = dims[pn[6]];
  172. var p1 = props[1];
  173. p1[borderConst + pn[0] + "Color"] = { start: lightColor, end: endColor };
  174. p1[borderConst + pn[0] + widthConst] = dims[pn[4].toLowerCase()];
  175. p1[borderConst + pn[2] + widthConst] = 0;
  176. p1[borderConst + pn[3] + widthConst] = 0;
  177. p1[pn[5].toLowerCase()] = { start: dims[pn[6]], end: dims[pn[5].toLowerCase()] };
  178. dojo.mixin(hs, staticProps);
  179. dojo.style(helperNode, hs);
  180. dojo.body().appendChild(helperNode);
  181. var finalize = function(){
  182. // helperNode.parentNode.removeChild(helperNode);
  183. dojo.destroy(helperNode);
  184. // fixes a flicker when the animation ends
  185. s.backgroundColor = endColor;
  186. s.visibility = "visible";
  187. };
  188. if(whichAnim == "last"){
  189. for(i in p0){
  190. p0[i] = { start: p0[i] };
  191. }
  192. p0[borderConst + pn[1] + "Color"] = { start: darkColor, end: endColor };
  193. p1 = p0;
  194. }
  195. if(!whichAnim || whichAnim == "first"){
  196. anims.push(dojo.animateProperty({
  197. node: helperNode,
  198. duration: duration,
  199. properties: p0
  200. }));
  201. }
  202. if(!whichAnim || whichAnim == "last"){
  203. anims.push(dojo.animateProperty({
  204. node: helperNode,
  205. duration: duration,
  206. properties: p1,
  207. onEnd: finalize
  208. }));
  209. }
  210. // hide the original node
  211. dojo.connect(anims[0], "play", function(){
  212. helperNode.style.visibility = "visible";
  213. s.visibility = "hidden";
  214. });
  215. return dojo.fx.chain(anims); // dojo.Animation
  216. }
  217. dojox.fx.flipCube = function(/*Object*/ args){
  218. // summary: An extension to `dojox.fx.flip` providing a more 3d-like rotation
  219. //
  220. // description:
  221. // An extension to `dojox.fx.flip` providing a more 3d-like rotation.
  222. // Behaves the same as `dojox.fx.flip`, using the same attributes and
  223. // other standard `dojo.Animation` properties.
  224. //
  225. // example:
  226. // See `dojox.fx.flip`
  227. var anims = [],
  228. mb = dojo.marginBox(args.node),
  229. shiftX = mb.w / 2,
  230. shiftY = mb.h / 2,
  231. dims = {
  232. top: {
  233. pName: "height",
  234. args:[
  235. {
  236. whichAnim: "first",
  237. dir: "top",
  238. shift: -shiftY
  239. },
  240. {
  241. whichAnim: "last",
  242. dir: "bottom",
  243. shift: shiftY
  244. }
  245. ]
  246. },
  247. right: {
  248. pName: "width",
  249. args:[
  250. {
  251. whichAnim: "first",
  252. dir: "right",
  253. shift: shiftX
  254. },
  255. {
  256. whichAnim: "last",
  257. dir: "left",
  258. shift: -shiftX
  259. }
  260. ]
  261. },
  262. bottom: {
  263. pName: "height",
  264. args:[
  265. {
  266. whichAnim: "first",
  267. dir: "bottom",
  268. shift: shiftY
  269. },
  270. {
  271. whichAnim: "last",
  272. dir: "top",
  273. shift: -shiftY
  274. }
  275. ]
  276. },
  277. left: {
  278. pName: "width",
  279. args:[
  280. {
  281. whichAnim: "first",
  282. dir: "left",
  283. shift: -shiftX
  284. },
  285. {
  286. whichAnim: "last",
  287. dir: "right",
  288. shift: shiftX
  289. }
  290. ]
  291. }
  292. }
  293. ;
  294. var d = dims[args.dir || "left"],
  295. p = d.args
  296. ;
  297. args.duration = args.duration ? args.duration * 2 : 500;
  298. args.depth = .8;
  299. args.axis = "cube";
  300. for(var i = p.length - 1; i >= 0; i--){
  301. dojo.mixin(args, p[i]);
  302. anims.push(dojox.fx.flip(args));
  303. }
  304. return dojo.fx.combine(anims);
  305. };
  306. dojox.fx.flipPage = function(/*Object*/ args){
  307. // summary: An extension to `dojox.fx.flip` providing a page flip like animation.
  308. //
  309. // description:
  310. // An extension to `dojox.fx.flip` providing a page flip effect.
  311. // Behaves the same as `dojox.fx.flip`, using the same attributes and
  312. // other standard `dojo.Animation` properties.
  313. //
  314. // example:
  315. // See `dojox.fx.flip`
  316. var n = args.node,
  317. coords = dojo.coords(n, true),
  318. x = coords.x,
  319. y = coords.y,
  320. w = coords.w,
  321. h = coords.h,
  322. bgColor = dojo.style(n, "backgroundColor"),
  323. lightColor = args.lightColor || "#dddddd",
  324. darkColor = args.darkColor,
  325. helperNode = dojo.create("div"),
  326. anims = [],
  327. hn = [],
  328. dir = args.dir || "right",
  329. pn = {
  330. left: ["left", "right", "x", "w"],
  331. top: ["top", "bottom", "y", "h"],
  332. right: ["left", "left", "x", "w"],
  333. bottom: ["top", "top", "y", "h"]
  334. },
  335. shiftMultiplier = {
  336. right: [1, -1],
  337. left: [-1, 1],
  338. top: [-1, 1],
  339. bottom: [1, -1]
  340. }
  341. ;
  342. dojo.style(helperNode, {
  343. position: "absolute",
  344. width : w + "px",
  345. height : h + "px",
  346. top : y + "px",
  347. left : x + "px",
  348. visibility: "hidden"
  349. });
  350. var hs = [];
  351. for(var i = 0; i < 2; i++){
  352. var r = i % 2,
  353. d = r ? pn[dir][1] : dir,
  354. wa = r ? "last" : "first",
  355. endColor = r ? bgColor : lightColor,
  356. startColor = r ? endColor : args.startColor || n.style.backgroundColor
  357. ;
  358. hn[i] = dojo.clone(helperNode);
  359. var finalize = function(x){
  360. return function(){
  361. dojo.destroy(hn[x]);
  362. }
  363. }(i)
  364. ;
  365. dojo.body().appendChild(hn[i]);
  366. hs[i] = {
  367. backgroundColor: r ? startColor : bgColor
  368. };
  369. hs[i][pn[dir][0]] = coords[pn[dir][2]] + shiftMultiplier[dir][0] * i * coords[pn[dir][3]] + "px";
  370. dojo.style(hn[i], hs[i]);
  371. anims.push(dojox.fx.flip({
  372. node: hn[i],
  373. dir: d,
  374. axis: "shortside",
  375. depth: args.depth,
  376. duration: args.duration / 2,
  377. shift: shiftMultiplier[dir][i] * coords[pn[dir][3]] / 2,
  378. darkColor: darkColor,
  379. lightColor: lightColor,
  380. whichAnim: wa,
  381. endColor: endColor
  382. }));
  383. dojo.connect(anims[i], "onEnd", finalize);
  384. }
  385. return dojo.fx.chain(anims);
  386. };
  387. dojox.fx.flipGrid = function(/*Object*/ args){
  388. // summary: An extension to `dojox.fx.flip` providing a decomposition in rows * cols flipping elements
  389. //
  390. // description:
  391. // An extension to `dojox.fx.flip` providing a page flip effect.
  392. // Behaves the same as `dojox.fx.flip`, using the same attributes and
  393. // other standard `dojo.Animation` properties and
  394. //
  395. // cols: Integer columns
  396. // rows: Integer rows
  397. //
  398. // duration: the single flip duration
  399. //
  400. // example:
  401. // See `dojox.fx.flip`
  402. var rows = args.rows || 4,
  403. cols = args.cols || 4,
  404. anims = [],
  405. helperNode = dojo.create("div"),
  406. n = args.node,
  407. coords = dojo.coords(n, true),
  408. x = coords.x,
  409. y = coords.y,
  410. nw = coords.w,
  411. nh = coords.h,
  412. w = coords.w / cols,
  413. h = coords.h / rows,
  414. cAnims = []
  415. ;
  416. dojo.style(helperNode, {
  417. position: "absolute",
  418. width: w + "px",
  419. height: h + "px",
  420. backgroundColor: dojo.style(n, "backgroundColor")
  421. });
  422. for(var i = 0; i < rows; i++){
  423. var r = i % 2,
  424. d = r ? "right" : "left",
  425. signum = r ? 1 : -1
  426. ;
  427. // cloning
  428. var cn = dojo.clone(n);
  429. dojo.style(cn, {
  430. position: "absolute",
  431. width: nw + "px",
  432. height: nh + "px",
  433. top: y + "px",
  434. left: x + "px",
  435. clip: "rect(" + i * h + "px," + nw + "px," + nh + "px,0)"
  436. });
  437. dojo.body().appendChild(cn);
  438. anims[i] = [];
  439. for(var j = 0; j < cols; j++){
  440. var hn = dojo.clone(helperNode),
  441. l = r ? j : cols - (j + 1)
  442. ;
  443. var adjustClip = function(xn, yCounter, xCounter){
  444. return function(){
  445. if(!(yCounter % 2)){
  446. dojo.style(xn, {
  447. clip: "rect(" + yCounter * h + "px," + (nw - (xCounter + 1) * w ) + "px," + ((yCounter + 1) * h) + "px,0px)"
  448. });
  449. }else{
  450. dojo.style(xn, {
  451. clip: "rect(" + yCounter * h + "px," + nw + "px," + ((yCounter + 1) * h) + "px," + ((xCounter + 1) * w) + "px)"
  452. });
  453. }
  454. }
  455. }(cn, i, j);
  456. dojo.body().appendChild(hn);
  457. dojo.style(hn, {
  458. left: x + l * w + "px",
  459. top: y + i * h + "px",
  460. visibility: "hidden"
  461. });
  462. var a = dojox.fx.flipPage({
  463. node: hn,
  464. dir: d,
  465. duration: args.duration || 900,
  466. shift: signum * w/2,
  467. depth: .2,
  468. darkColor: args.darkColor,
  469. lightColor: args.lightColor,
  470. startColor: args.startColor || args.node.style.backgroundColor
  471. }),
  472. removeHelper = function(xn){
  473. return function(){
  474. dojo.destroy(xn);
  475. }
  476. }(hn)
  477. ;
  478. dojo.connect(a, "play", this, adjustClip);
  479. dojo.connect(a, "play", this, removeHelper);
  480. anims[i].push(a);
  481. }
  482. cAnims.push(dojo.fx.chain(anims[i]));
  483. }
  484. dojo.connect(cAnims[0], "play", function(){
  485. dojo.style(n, {visibility: "hidden"});
  486. });
  487. return dojo.fx.combine(cAnims);
  488. };
  489. }