You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TransitionsAnimation.java 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. * Copyright 2013, The gwtquery team.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.google.gwt.query.client.plugins.effects;
  17. import static com.google.gwt.query.client.GQuery.$;
  18. import static com.google.gwt.query.client.GQuery.$$;
  19. import static com.google.gwt.query.client.plugins.effects.ClipAnimation.getNormalizedValue;
  20. import com.google.gwt.dom.client.Element;
  21. import com.google.gwt.query.client.Properties;
  22. import com.google.gwt.query.client.plugins.Effects.GQAnimation;
  23. import com.google.gwt.query.client.plugins.effects.ClipAnimation.Action;
  24. import com.google.gwt.query.client.plugins.effects.ClipAnimation.Corner;
  25. import com.google.gwt.query.client.plugins.effects.ClipAnimation.Direction;
  26. import com.google.gwt.query.client.plugins.effects.Fx.TransitFx;
  27. import com.google.gwt.regexp.shared.MatchResult;
  28. import com.google.gwt.user.client.Timer;
  29. import java.util.List;
  30. /**
  31. * Animation effects on any numeric CSS3 property or transformation
  32. * using CSS3 transitions.
  33. */
  34. public class TransitionsAnimation extends PropertiesAnimation {
  35. /**
  36. * TransitionAnimation with Clip capabilities.
  37. */
  38. public static class TransitionsClipAnimation extends TransitionsAnimation {
  39. private Action action;
  40. private Corner corner;
  41. private Direction direction;
  42. private Action currentAction;
  43. @Override
  44. public GQAnimation setProperties(Properties p) {
  45. corner = Corner.CENTER;
  46. try {
  47. corner = Corner.valueOf(getNormalizedValue("clip-origin", p));
  48. } catch (Exception e) {
  49. }
  50. direction = Direction.BIDIRECTIONAL;
  51. try {
  52. direction = Direction.valueOf(getNormalizedValue("clip-direction", p));
  53. } catch (Exception e) {
  54. }
  55. try {
  56. action = Action.valueOf(getNormalizedValue("clip-action", p));
  57. } catch (Exception e) {
  58. }
  59. return super.setProperties(p);
  60. }
  61. public void onStart() {
  62. boolean hidden = !t.isVisible();
  63. super.onStart();
  64. if (action == null) {
  65. return;
  66. }
  67. currentAction = action != Action.TOGGLE ? action : hidden ? Action.SHOW : Action.HIDE;
  68. int bit = currentAction == Action.HIDE ? 1 : 0;
  69. String originX = "left", originY = "top";
  70. int scaleXini = 0 ^ bit, scaleYini = scaleXini;
  71. int scaleXend = 1 ^ bit, scaleYend = scaleXend;
  72. if (direction == Direction.VERTICAL) {
  73. scaleXini = scaleXend = 1;
  74. }
  75. if (direction == Direction.HORIZONTAL) {
  76. scaleYini = scaleYend = 1;
  77. }
  78. if (corner == Corner.CENTER) {
  79. originX = originY = "center";
  80. }
  81. if (corner == Corner.TOP_RIGHT || corner == Corner.BOTTOM_RIGHT) {
  82. originX = "right";
  83. }
  84. if (corner == Corner.BOTTOM_LEFT || corner == Corner.BOTTOM_RIGHT) {
  85. originY = "bottom";
  86. }
  87. t.show().css("transformOrigin", originX + " " + originY);
  88. effects.add(new TransitFx("scale", "", scaleXini + " " + scaleYini, scaleXend + " " + scaleYend, ""));
  89. }
  90. @Override
  91. public void onComplete() {
  92. super.onComplete();
  93. if (action == null) {
  94. return;
  95. }
  96. if (currentAction == Action.HIDE) {
  97. t.hide();
  98. }
  99. t.css("transformOrigin", "");
  100. t.css("transform", "");
  101. }
  102. }
  103. public static TransitFx computeFxProp(Element e, String key, String val, boolean hidden) {
  104. Transitions g = $(e).as(Transitions.Transitions);
  105. String unit = REGEX_NON_PIXEL_ATTRS.test(key) ? "" : "px";
  106. if ("toggle".equals(val)) {
  107. val = hidden ? "show" : "hide";
  108. }
  109. if ("show".equals(val) && !hidden || "hide".equals(val) && hidden) {
  110. return null;
  111. }
  112. if (hidden) {
  113. g.show();
  114. }
  115. String cur = g.css(key, true);
  116. String trsStart = cur.matches("auto|initial") ? "" : cur, trsEnd = trsStart;
  117. if ("show".equals(val)) {
  118. g.saveCssAttrs(key);
  119. if (trsStart.isEmpty()) {
  120. trsStart = "0";
  121. }
  122. if (REGEX_SCALE_ATTRS.test(key)) {
  123. trsEnd = "1";
  124. }
  125. } else if ("hide".equals(val)) {
  126. g.saveCssAttrs(key);
  127. if (trsStart.isEmpty() && REGEX_SCALE_ATTRS.test(key)) {
  128. trsStart = "1";
  129. }
  130. trsEnd = "0";
  131. } else {
  132. MatchResult parts = REGEX_SYMBOL_NUMBER_UNIT.exec(val);
  133. if (parts != null) {
  134. String part1 = parts.getGroup(1);
  135. String part2 = parts.getGroup(2);
  136. String part3 = parts.getGroup(3);
  137. trsEnd = "" + Double.parseDouble(part2);
  138. if (part3 != null && !part3.isEmpty()) {
  139. unit = part3;
  140. }
  141. if (trsStart.isEmpty()) {
  142. trsStart = REGEX_SCALE_ATTRS.test(key) ? "1" : "0";
  143. }
  144. if (part1 != null && !part1.isEmpty()) {
  145. double n = "-=".equals(part1) ? -1 : 1;
  146. double st = 0;
  147. MatchResult sparts = REGEX_SYMBOL_NUMBER_UNIT.exec(trsStart);
  148. if (sparts != null) {
  149. st = Double.parseDouble(sparts.getGroup(2));
  150. unit = sparts.getGroup(3) == null || sparts.getGroup(3).isEmpty() ? unit : sparts.getGroup(3);
  151. }
  152. trsStart = "" + st;
  153. double en = Double.parseDouble(trsEnd);
  154. trsEnd = "" + (st + n * en);
  155. }
  156. // Deal with non px units like "%"
  157. if (!unit.isEmpty() && !"px".equals(unit) && trsStart.matches(NUMBER)) {
  158. double start = Double.parseDouble(trsStart);
  159. if (start != 0) {
  160. double to = Double.parseDouble(trsEnd);
  161. g.css(key, to + unit);
  162. start = to * start / g.cur(key, true);
  163. trsStart = "" + start;
  164. g.css(key, start + unit);
  165. }
  166. }
  167. } else {
  168. trsStart = "";
  169. trsEnd = val;
  170. if (trsStart.isEmpty()) {
  171. trsStart = REGEX_SCALE_ATTRS.test(key) ? "1" : "0";
  172. }
  173. }
  174. }
  175. if (trsStart.matches(NUMBER)) {
  176. trsStart += unit;
  177. }
  178. if (trsEnd.matches(NUMBER)) {
  179. trsEnd += unit;
  180. }
  181. return new TransitFx(key, val, trsStart, trsEnd, unit);
  182. }
  183. protected Transitions t;
  184. protected int delay = 0;
  185. private String oldTransitionValue;
  186. @Override
  187. public GQAnimation setProperties(Properties p) {
  188. delay = p.getInt("delay");
  189. return super.setProperties(p);
  190. }
  191. @Override
  192. public GQAnimation setElement(Element elem) {
  193. e = elem;
  194. g = t = $(elem).as(Transitions.Transitions);
  195. return this;
  196. }
  197. public TransitionsAnimation setDelay(int delay) {
  198. this.delay = delay;
  199. return this;
  200. }
  201. public Properties getFxProperties(boolean isStart) {
  202. Properties p = $$();
  203. for (int i = 0; i < effects.length(); i++) {
  204. TransitFx fx = (TransitFx) effects.get(i);
  205. String val = isStart ? fx.transitStart : fx.transitEnd;
  206. if (!val.isEmpty()) {
  207. p.set(fx.cssprop, val);
  208. }
  209. }
  210. return p;
  211. }
  212. @Override
  213. protected Fx getFx(Element e, String key, String val, boolean hidden) {
  214. return Transitions.invalidTransitionNamesRegex.test(key) ? null : computeFxProp(e, key, val, hidden);
  215. }
  216. @Override
  217. public void onUpdate(double progress) {
  218. }
  219. @Override
  220. public void onComplete() {
  221. t.css(Transitions.TRANSITION, oldTransitionValue);
  222. super.onComplete();
  223. }
  224. public void run(int duration) {
  225. // Calculate all Fx values for this animation
  226. onStart();
  227. // Compute initial properties
  228. Properties p = getFxProperties(true);
  229. t.css(p);
  230. // Some browsers need re-flow after setting initial properties (FF 24.4.0).
  231. t.offset();
  232. // Compute final properties
  233. p = getFxProperties(false);
  234. // Save old transition value
  235. oldTransitionValue = t.css(Transitions.TRANSITION);
  236. // Set new transition value
  237. String newTransitionValue = "";
  238. List<String> transProps = Transitions.filterTransitionPropertyNames(p);
  239. String attribs = duration + "ms" + " " + easing + " " + delay + "ms";
  240. for (String s : transProps) {
  241. newTransitionValue += (newTransitionValue.isEmpty() ? "" : ", ") + s + " " + attribs;
  242. }
  243. t.css(Transitions.TRANSITION, newTransitionValue);
  244. // Set new css properties so as the element is animated
  245. t.css(p);
  246. // Wait until transition has finished to run finish animation and dequeue
  247. new Timer() {
  248. public void run() {
  249. onComplete();
  250. }
  251. }.schedule(delay + duration);
  252. }
  253. }