]> source.dussan.org Git - gwtquery.git/commitdiff
Use CSS3 animations when available.
authorManuel Carrasco Moñino <manuel.carrasco.m@gmail.com>
Sun, 17 Nov 2013 21:36:14 +0000 (22:36 +0100)
committerManuel Carrasco Moñino <manuel.carrasco.m@gmail.com>
Sun, 17 Nov 2013 21:36:14 +0000 (22:36 +0100)
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Effects.java
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/ClipAnimation.java
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Fx.java
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/PropertiesAnimation.java
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/TransitionsAnimation.java

index 39d792dd4bd78f0d2a837f4176912ae1c53bc2ec..19d49b6b0f6f2f4495bf5d5f7a3135c9409e524e 100755 (executable)
@@ -27,6 +27,8 @@ import com.google.gwt.query.client.plugins.effects.Fx;
 import com.google.gwt.query.client.plugins.effects.PropertiesAnimation;
 import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.Easing;
 import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.EasingCurve;
+import com.google.gwt.query.client.plugins.effects.TransitionsAnimation;
+import com.google.gwt.query.client.plugins.effects.TransitionsAnimation.TransitionsClipAnimation;
 
 /**
  * Effects plugin for Gwt Query.
@@ -43,13 +45,13 @@ public class Effects extends QueuePlugin<Effects> {
     // Each Animation is associated to one element
     protected Element e;
     protected Properties prps;
-    
+
     protected GQAnimation setElement(Element element) {
       e = element;
       return this;
     }
     protected GQAnimation setProperties(Properties properties) {
-      prps = properties;
+      prps = properties == null ? Properties.create() : properties;
       return this;
     }
     protected void onStart() {
@@ -78,7 +80,6 @@ public class Effects extends QueuePlugin<Effects> {
     public static final int SLOW = 600;
   }
 
-
   public static final Class<Effects> Effects = GQuery.registerPlugin(
       Effects.class, new Plugin<Effects>() {
         public Effects init(GQuery gq) {
@@ -168,15 +169,24 @@ public class Effects extends QueuePlugin<Effects> {
   public Effects animate(Object stringOrProperties, final int duration,
       final Easing easing, final Function... funcs) {
 
+
     final Properties p = (stringOrProperties instanceof String)
         ? $$((String) stringOrProperties) : (Properties) stringOrProperties;
 
     for (Element e: elements()) {
-      queueAnimation(e, new PropertiesAnimation(easing, e, p, funcs), duration);
+      if (Fx.css3) {
+        new TransitionsAnimation(easing, e, p, funcs).run(duration);
+      } else {
+        queueAnimation(e, new PropertiesAnimation(easing, e, p, funcs), duration);
+      }
     }
     return this;
   }
 
+  private static native void set(Element e) /*-{
+    $wnd.eee = e;
+  }-*/;
+
   /**
    *
    * The animate() method allows you to create animation effects on any numeric
@@ -318,7 +328,11 @@ public class Effects extends QueuePlugin<Effects> {
       final ClipAnimation.Corner c, final ClipAnimation.Direction d,
       final int duration, final Function... f) {
     for (Element e : elements()) {
-      queueAnimation(e, new ClipAnimation(e, a, c, d, f), duration);
+      if (Fx.css3) {
+        new TransitionsClipAnimation(e, a, c, d, null, null, f).run(duration);
+      } else {
+        queueAnimation(e, new ClipAnimation(e, a, c, d, f), duration);
+      }
     }
     return this;
   }
@@ -468,7 +482,7 @@ public class Effects extends QueuePlugin<Effects> {
   public Effects fadeOut(int millisecs, Function... f) {
     return animate("opacity: 'hide'", millisecs, f);
   };
-  
+
   /**
    * Fade the opacity of all matched elements to a specified opacity and firing
    * an optional callback after completion. Only the opacity is adjusted for
@@ -478,7 +492,7 @@ public class Effects extends QueuePlugin<Effects> {
   public Effects fadeTo(double opacity, Function... f) {
     return fadeTo(Speed.DEFAULT, opacity, f);
   }
-  
+
   /**
    * Fade the opacity of all matched elements to a specified opacity and firing
    * an optional callback after completion. Only the opacity is adjusted for
index 2f928284969b470bbab102a7749006b2779c278e..e0047fc087a49f01b3c78b7ca6db8a3837ac67d2 100755 (executable)
@@ -15,7 +15,6 @@
  */
 package com.google.gwt.query.client.plugins.effects;
 
-
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.query.client.Function;
 import com.google.gwt.query.client.GQuery;
@@ -71,18 +70,14 @@ public class ClipAnimation extends PropertiesAnimation {
       direction = Direction.valueOf(getNormalizedValue("clip-direction", p));
     } catch (Exception e) {
     }
-    action = Action.TOGGLE;
     try {
       action = Action.valueOf(getNormalizedValue("clip-action", p));
     } catch (Exception e) {
     }
-
-    this.funcs = funcs;
-    e = elem;
     g = GQuery.$(e).as(Effects.Effects);
   }
 
-  private String getNormalizedValue(String value, Properties p) {
+  private static String getNormalizedValue(String value, Properties p) {
     return JsUtils.hyphenize(p.getStr("clip-direction")).replace("-", "_").toUpperCase();
   }
 
@@ -92,8 +87,6 @@ public class ClipAnimation extends PropertiesAnimation {
     this.action = a;
     this.corner = c;
     this.direction = d;
-    this.funcs = funcs;
-    e = elem;
     g = GQuery.$(e).as(Effects.Effects);
   }
 
@@ -175,7 +168,6 @@ public class ClipAnimation extends PropertiesAnimation {
       bottom = h;
     }
 
-    String rect = top + "px " + right + "px " + bottom + "px  " + left + "px";
-    g.css("clip", "rect(" + rect + ")");
+    g.css("clip", "rect(" + top + "px " + right + "px " + bottom + "px  " + left + "px)");
   }
 }
index a2a374b8be8b6a90e1c6f82e561053bc4fa7fa92..e497d8f32ed6194e020abe166f57acf8a1fcdce2 100644 (file)
@@ -18,6 +18,8 @@ public class Fx {
    */
   public static boolean off = false;
 
+  public static boolean css3 = Transitions.transition != null;
+
   /**
    * A pojo to store css3 transition values.
    */
index 36c5ddc8d10385de7f0efa81d33a499175bb3749..d18a220a89a800d95601a37097bb9947b08bdb1a 100755 (executable)
@@ -140,7 +140,7 @@ public class PropertiesAnimation extends GQAnimation {
   protected static final RegExp REGEX_SYMBOL_NUMBER_UNIT = RegExp.compile("^([+-]=)?([0-9+-.]+)(.*)?$");
 
   protected static final RegExp REGEX_NON_PIXEL_ATTRS = 
-      RegExp.compile("z-?index|font-?weight|opacity|zoom|line-?height|^\\$", "i");
+      RegExp.compile("z-?index|font-?weight|opacity|zoom|line-?height|scale|rotation|^\\$", "i");
 
   private static final RegExp REGEX_COLOR_ATTR = RegExp.compile(".*color$", "i");
 
@@ -270,7 +270,7 @@ public class PropertiesAnimation extends GQAnimation {
 
   protected Easing easing;
   protected JsObjectArray<Fx> effects;
-  protected Function[] funcs;
+  private Function[] funcs;
   private Effects g;
 
   public PropertiesAnimation(Element elem, Properties p, Function... funcs) {
index 4d195e2172536a2820fe50d49609916b12b9bb3c..dd23c3d1bae080cda4e8eeb8f9a86194030145e5 100644 (file)
@@ -34,11 +34,11 @@ import com.google.gwt.user.client.DOM;
 
 /**
  * Transitions and transformation plugin for gQuery.
- * 
+ *
  * It is inspired on jquery.transit (http://github.com/rstacruz/jquery.transit)
  *
  * Usage examples:
- * <pre> 
+ * <pre>
 
     $("#foo")
      .transition("{ opacity: 0.1, scale: 2, x: 50, y: 50 }", 5000, "easeOutBack", 0)
@@ -53,25 +53,35 @@ import com.google.gwt.user.client.DOM;
  * </pre>
  */
 public class Transitions extends GQuery {
-  
+
   /**
    * A dictionary class with all the properties of an element transform
    * which is able to return the correct syntax for setting css properties.
    */
   public static class Transform  {
-    
+
     private static final RegExp transform3dRegex = RegExp.compile("^(rotate([XY]|3d)|perspective)$");
-    
+
     private HashMap<String, List<String>> map = new HashMap<String, List<String>>();
 
     public Transform(String s) {
       parse(s);
     }
-    
-    public List<String> get(String prop) {
-      return map.get(prop);
+
+    public String get(String prop) {
+      return listToStr(map.get(prop), ",");
+    }
+
+    private String listToStr(List<String> l, String sep) {
+      String v = "";
+      if (l != null) {
+        for (String s : l) {
+          v += (v.isEmpty() ? "" : sep) + s;
+        }
+      }
+      return v;
     }
-    
+
     private void parse(String s) {
       if (s != null) {
         RegExp re = RegExp.compile("([a-zA-Z0-9]+)\\((.*?)\\)", "g");
@@ -80,11 +90,11 @@ public class Transitions extends GQuery {
         }
       }
     }
-    
+
     public void set(String prop, String ...val) {
       setter(prop, val);
     }
-    
+
     public void setFromString(String prop, String ...val) {
       if (val.length == 1 && val[0] instanceof String) {
         String[] vals = ((String)val[0]).split("[\\s*,\\s*]");
@@ -93,7 +103,7 @@ public class Transitions extends GQuery {
         set(prop, val);
       }
     }
-    
+
     private void setter(String prop, String ...val) {
       if (prop.matches("(rotate[XY]?|skew[XY])")) {
         map.put(prop, unit(val[0], "deg"));
@@ -123,7 +133,7 @@ public class Transitions extends GQuery {
         map.put("translate", Arrays.asList(map.get("translateX").get(0), map.get("translateY").get(0)));
       }
     }
-    
+
     /**
      * Converts the dictionary to a transition css string.
      */
@@ -133,44 +143,41 @@ public class Transitions extends GQuery {
       String ret = "";
       for (Entry<String, List<String>> e: map.entrySet()) {
         if (has3d || !transform3dRegex.test(e.getKey())) {
-          String v = "";
-          for (String s : e.getValue()) {
-            v += (v.isEmpty() ? "" : ",") + s;
-          }
+          String v = listToStr(e.getValue(), ",");
           ret += (ret.isEmpty() ? "" : " ") + e.getKey() + "(" + v + ")";
         }
       }
       return ret;
     }
-    
+
     private List<String> unit(String val, String unit) {
       return Arrays.asList(val + (val.endsWith(unit) ? "" : unit));
     }
   }
-  
+
   // Used to check supported properties in the browser
   private static Style divStyle = DOM.createDiv().getStyle();
-  
+
   private static final String prefix = browser.msie ? "ms" : browser.opera ? "o" : browser.mozilla ? "moz" : browser.webkit ? "webkit" : "";
   private static final String transform = getVendorPropertyName("transform");
   private static final String TRANSFORM = "_t_";
   private static final String transformOrigin = getVendorPropertyName("transformOrigin");
-  
+
   protected static final RegExp transformRegex = RegExp.compile("^(scale|translate|rotate([XY]|3d)?|perspective|skew[XY]|x|y)$");
-  private static final String transition = getVendorPropertyName("transition");
-  
+  protected static final String transition = getVendorPropertyName("transition");
+
   private static final String transitionDelay = getVendorPropertyName("transitionDelay");
   private static final String transitionEnd = browser.mozilla || browser.msie ? "transitionend" : (prefix + "transitionEnd");
-  
+
   public static boolean has3d = supportsTransform3d();
-  
+
   public static final Class<Transitions> Transitions = GQuery.registerPlugin(
       Transitions.class, new Plugin<Transitions>() {
         public Transitions init(GQuery gq) {
           return new Transitions(gq);
         }
       });
-  
+
   private static String getVendorPropertyName(String prop) {
     // we prefer vendor specific names by default
     String vendorProp =  JsUtils.camelize("-" + prefix + "-" + prop);
@@ -186,40 +193,42 @@ public class Transitions extends GQuery {
     }
     return null;
   }
-  
+
   private static String property(String prop) {
     if (transformRegex.test(prop)) {
       return transform;
     }
     return prop.replaceFirst("^(margin|padding).+$", "$1");
   }
-  
+
   private static boolean supportsTransform3d() {
     String rotate = "rotateY(1deg)";
     divStyle.setProperty(transform, rotate);
     rotate = divStyle.getProperty(transform);
     return rotate != null && !rotate.isEmpty();
   }
-  
+
   protected Transitions(GQuery gq) {
     super(gq);
   }
 
-  @Override 
+  @Override
   public String css(String prop, boolean force) {
     if ("transform".equals(prop)) {
-      Transform t = data(TRANSFORM);
-      return t == null ? "" : t.toString();
+      return isEmpty() ? "" : getTransform(get(0), null).toString();
     } else if ("transformOrigin".equals(prop)) {
       return super.css(transformOrigin, force);
     } else if ("transition".equals(prop)) {
       return super.css(transition, force);
+    } else if (transformRegex.test(prop)) {
+      return isEmpty() ? "" : getTransform(get(0), null).get(prop);
     } else {
-      return super.css(prop, force);
+      String ret =  super.css(prop, force);
+      return ret;
     }
   }
-  
-  @Override 
+
+  @Override
   public Transitions css(String prop, String value) {
     if ("transform".equals(prop)) {
       for (Element e : elements()) {
@@ -241,7 +250,7 @@ public class Transitions extends GQuery {
     }
     return this;
   }
-  
+
   private List<String> filterPropertyNames(Properties p) {
     List<String> ret = new ArrayList<String>();
     for (String s : p.keys()) {
@@ -251,7 +260,7 @@ public class Transitions extends GQuery {
       if (m != null) {
         c = m;
       }
-      // chrome needs transition:-webkit-transform instead of transition:transform 
+      // chrome needs transition:-webkit-transform instead of transition:transform
       c = JsUtils.hyphenize(c);
       if (!ret.contains(c)) {
         ret.add(c);
@@ -259,7 +268,7 @@ public class Transitions extends GQuery {
     }
     return ret;
   }
-  
+
   private Transform getTransform(Element e, String initial) {
     Transform t = data(e, TRANSFORM);
     if (t == null || initial != null && !initial.isEmpty() ) {
@@ -268,11 +277,11 @@ public class Transitions extends GQuery {
     }
     return t;
   }
-  
+
   /**
    * The transition() method allows you to create animation effects on any numeric HTML Attribute,
    * CSS property, or color using CSS3 transformations and transitions.
-   * 
+   *
    * It works similar to animate(), supports chainning and queueing and an extra parameter for
    * delaying the animation.
    *
@@ -289,7 +298,7 @@ public class Transitions extends GQuery {
     if (isEmpty()) {
       return this;
     }
-    
+
     final Properties p = (stringOrProperties instanceof String) ? $$((String) stringOrProperties) : (Properties) stringOrProperties;
 
     final String oldTransitions = css(transition);
@@ -297,14 +306,14 @@ public class Transitions extends GQuery {
     if (easing == null) {
       easing = EasingCurve.ease;
     }
-    
+
     String attribs = duration + "ms" + " "  + easing.toString() + " " + delay + "ms";
     List<String> props = filterPropertyNames(p);
     String value  = "";
     for (String s : props) {
       value += (value.isEmpty() ? "" : ", ") + s + " " + attribs;
     }
-    
+
     final String transitionValue = value;
 
     // Use gQuery queue, so as we can chain transitions, animations etc.
@@ -313,12 +322,10 @@ public class Transitions extends GQuery {
       $(this)
         // Configure animation using transition property
         .css(transition, transitionValue)
-        // Set all css properties for this transition using the css method in this class 
-        .as(Transitions).css(p)
-        // prevent memory leak
-        .removeData(TRANSFORM);
+        // Set all css properties for this transition using the css method in this class
+        .as(Transitions).css(p);
     }});
-    
+
     // restore oldTransitions in the element, and use the queue to prevent more effects being run.
     // TODO: Use transitionEnd events once GQuery supports non-bit events
     delay(duration + delay, new Function(){public void f() {
@@ -327,7 +334,7 @@ public class Transitions extends GQuery {
         .css(transition, oldTransitions)
         .each(funcs);
     }});
-    
+
     return this;
   }
 
index 32e689d7a8dad60b55f4e683e6ee7c27a42ad2a4..14865119caa76b788a73ff454e1e467b02f111a6 100755 (executable)
@@ -21,6 +21,9 @@ import com.google.gwt.dom.client.Element;
 import com.google.gwt.query.client.Function;
 import com.google.gwt.query.client.Properties;
 import com.google.gwt.query.client.js.JsObjectArray;
+import com.google.gwt.query.client.plugins.effects.ClipAnimation.Action;
+import com.google.gwt.query.client.plugins.effects.ClipAnimation.Corner;
+import com.google.gwt.query.client.plugins.effects.ClipAnimation.Direction;
 import com.google.gwt.query.client.plugins.effects.Fx.TransitFx;
 import com.google.gwt.regexp.shared.MatchResult;
 
@@ -29,7 +32,66 @@ import com.google.gwt.regexp.shared.MatchResult;
  * using CSS3 transitions
  */
 public class TransitionsAnimation extends PropertiesAnimation {
-  
+
+  public static class TransitionsClipAnimation extends TransitionsAnimation {
+
+    private Action action;
+    private Corner corner;
+    private Direction direction;
+    private Action currentAction;
+
+    public TransitionsClipAnimation(Element elem, Action a, Corner c, Direction d, Easing easing,
+        Properties p, final Function... funcs) {
+      super(easing, elem, p, funcs);
+      this.action = a;
+      this.corner = c;
+      this.direction = d;
+    }
+
+    public void onStart() {
+      boolean hidden = !g.isVisible();
+
+      super.onStart();
+
+      currentAction = action != Action.TOGGLE ? action :  hidden ? Action.SHOW : Action.HIDE;
+      int bit = currentAction == Action.HIDE ? 1 : 0;
+
+      String originX = "left", originY = "top";
+      int scaleXini = 0^bit, scaleYini = scaleXini;
+      int scaleXend = 1^bit, scaleYend = scaleXend;
+
+      if (direction == Direction.VERTICAL) {
+        scaleXini = scaleXend = 1;
+      }
+      if (direction == Direction.HORIZONTAL) {
+        scaleYini = scaleYend = 1;
+      }
+      if (corner == Corner.CENTER) {
+        originX = originY = "center";
+      }
+      if (corner == Corner.TOP_RIGHT || corner == Corner.BOTTOM_RIGHT) {
+        originX = "right";
+      }
+      if (corner == Corner.BOTTOM_LEFT || corner == Corner.BOTTOM_RIGHT) {
+        originY = "bottom";
+      }
+
+      g.show().css("transformOrigin", originX + " " + originY);
+
+      effects.add(new TransitFx("scale", "", scaleXini + " " + scaleYini, scaleXend + " " + scaleYend, ""));
+    }
+
+    @Override
+    public void onComplete() {
+      super.onComplete();
+      if (currentAction == Action.HIDE) {
+        g.hide();
+      }
+      g.css("transformOrigin", "");
+      g.css("transform", "scale(1 1)");
+    }
+  }
+
   public static Fx computeFxProp(Element e, String key, String val, boolean hidden) {
     Transitions g = $(e).as(Transitions.Transitions);
     String unit = "";
@@ -47,35 +109,28 @@ public class TransitionsAnimation extends PropertiesAnimation {
 
     String cur = g.css(key, true);
     String trsStart = cur, trsEnd = trsStart;
-    
+
     if ("show".equals(val)) {
       g.saveCssAttrs(key);
       trsStart = "0";
     } else if ("hide".equals(val)) {
-      if (hidden) {
-        return null;
-      }
       g.saveCssAttrs(key);
       trsEnd = "0";
     } else {
       MatchResult parts = REGEX_SYMBOL_NUMBER_UNIT.exec(val);
       if (parts != null) {
         unit = REGEX_NON_PIXEL_ATTRS.test(key) || Transitions.transformRegex.test(key) ? "" : "px";
-        
+
         String part1 = parts.getGroup(1);
         String part2 = parts.getGroup(2);
         String part3 = parts.getGroup(3);
         trsEnd = "" + Double.parseDouble(part2);
-        
+
         if (unit.isEmpty() && part3 != null) {
           unit = part3;
         }
         if (trsStart.isEmpty()) {
-          trsStart = "0";
-        }
-        
-        if (!trsStart.endsWith(unit)) {
-          trsStart += unit;
+          trsStart = key.matches("scale") ? "1" : "0";
         }
 
         if (part1 != null && !part1.isEmpty()) {
@@ -85,14 +140,15 @@ public class TransitionsAnimation extends PropertiesAnimation {
           trsEnd = "" + (st + (n*en));
         }
       } else {
-        trsStart = trsEnd = val;
+        trsStart = "";
+        trsEnd = val;
       }
     }
     return new TransitFx(key, val, trsStart, trsEnd, unit);
   }
 
-  private Transitions g;
-  
+  protected Transitions g;
+
   public TransitionsAnimation(Element elem, Properties p, Function... funcs) {
     this(null, elem, p, funcs);
   }
@@ -106,7 +162,10 @@ public class TransitionsAnimation extends PropertiesAnimation {
     Properties p = $$();
     for (int i = 0; i < effects.length(); i++) {
       TransitFx fx = (TransitFx)effects.get(i);
-      p.set(fx.cssprop, (isStart ? fx.transitStart : fx.transitEnd) + fx.unit);
+      String val = isStart ? fx.transitStart : fx.transitEnd;
+      if (!val.isEmpty()) {
+        p.set(fx.cssprop, val + fx.unit);
+      }
     }
     return p;
   }
@@ -135,13 +194,19 @@ public class TransitionsAnimation extends PropertiesAnimation {
     }
   }
 
+  @Override
+  public void onUpdate(double progress) {
+  }
+
   @Override
   public void run(int duration) {
     onStart();
     Properties p = getFxProperties(true);
     g.css(p);
+    // TODO: Reflow, it seems it is not needed in chrome and FF, check other browsers
+    // g.css("offsetHeight");
     p = getFxProperties(false);
-    g.transition(p, duration - 150, easing, 0, new Function(){public void f() {
+    g.transition(p, duration, easing, 0, new Function(){public void f() {
       onComplete();
     }});
   }