flip.js 14 KB

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